C# 多线程系列(三)
线程池
创建线程需要时间,如果有不同的小任务要完成,就可以事先创建许多线程,在应完成这些任务时发出请求。这个线程数最好在需要更多线程时增加,在需要释放资源时减少。
不需要自己创建这样的一个列表。该列表由ThreadPool类托管。该类会在需要时增加线程池中线程数,直到最大的线程数。
- 可以指定创建线程池时立即启动的最小线程数,以及线程池中可用的最大线程数。
- 如果更多的作业要处理,线程池中的线程个数也到了极限,最新的作业就要排队,且必须等待线程完成其作业。
- 线程池中的线程都是后台线程,不能把入池的线程改为前台线程。
- 不能给入池的线程设置优先级和名字。
- 对于COM对象,入池的所有线程都是多线程单元线程。许多COM对象都需要单线程单元线程。
- 入池的线程只能用于时间比较短的任务。如果线程要一直运行,就应该使用Thread类创建一个线程。
static void Main()
{
int nWorkerThreads;
int nCompletionPorThreads;
ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPorThreads);
//ThreadPool.SetMaxThreads(500, 500);
lib.print("Max worker threads : " + nWorkerThreads);
lib.print("I/O completion threads: " + nCompletionPorThreads); for(int i=; i<; i++)
{
ThreadPool.QueueUserWorkItem(JobForAThread);//将方法排入队列以便执行。 此方法在有线程池线程变得可用时执行。
}
Thread.Sleep();
} static void JobForAThread(object state)
{
for(int i = ; i<; i++)
{
Console.WriteLine("loop {0}, running inside pooled thread {1}", i, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
}
}
示例应用程序首先要读取工作线程和I/O线程的最大线程数,把这些信息写入控制台中。接着在for循环中,调用Thread.QueueuserWorkItm()方法,传递一个WaitCallback类型的委托,把JobForAThread()方法赋予线程池中的线程。
线程池收到这个请求后,就会从池中选择一个线程,来调用该方法。如果线程池还没有运行,就会创建一个线程池,并启动第一个线程。如果线程池己经在运行,且有一个空闲线程来完成该任务,就把该作业传递给这个线程。
异步委托
创建线程最简单的方式是定义一个委托,然后异步调用它。
委托使用线程池完成异步任务,当没有前台线程运行时,异步委托将直接结束。
static void Main(string[] args)
{
Action action = new Action(() =>
{
for(int i=; i<; i++)
{
lib.put(".");
Thread.Sleep();
}
}); AsyncCallback calback = (IAsyncResult result) =>
{
Thread.Sleep();
lib.print(result.AsyncState);
};
var rs = action.BeginInvoke(calback, "Begin Invoke");//如此,便启动了异步委托。下面用不同方法等待异步委托完成。 //方法一,用EndInvoke方法,该方法会一直等待,直到委托完成任务为止。
action.EndInvoke(rs); //方法二,使用IAsyncResult相关联的等待句柄。使用AsyncWaitHandle属性可以访问等待句柄。
//这个属性返回一个WaitHandle类型对象,它可以等待委托线程完成其任务。参数是最长等待时间,
//-1表示无限等待。如果当前实例收到信号,则返回为 true;否则为 false。
rs.AsyncWaitHandle.WaitOne(); //方法三,不断检查
while (true)
{
if (!rs.IsCompleted)
{
Thread.Sleep();
}
else
{
break;
}
} //因为callback最终是异步线程回调的,所以,如果直接退出,callback将无法打印出Begin Invoke。
Thread.Sleep();
}
任务
System.Threading.Tasks包含的类抽象出了线程功能,在后台使用ThreadPool。任务表示应完成的某个单元工作,这个单元工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主线程。使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。
- 启动任务
可以使用实例化的TaskFactory类,在其中把TaskMethod()方法传递给StarNew()方法,就会立刻启动任务。也可以使用Task类的构造函数。实例化Task对象时,任务不会立即运行,而是指定Created状态。接着调用Task类的Start()方法,来启动任务。使用Task类时,还可以调用TunSynchronously()方法。
static void Main(string[] args)
{
Task t1 = new Task(DoOnFirst);
t1.Start(); TaskFactory tf = new TaskFactory();
Task t2 = tf.StartNew(DoOnFirst); Task t3 = Task.Factory.StartNew(DoOnFirst); Task.WaitAll(t1, t2, t3);
}
static void DoOnFirst()
{
lib.print("Task.CurrentId :" + Task.CurrentId);
lib.print("-----------");
Thread.Sleep();
}
- 连续的任务
连续任务通过在任务上调用ContinueWith()方法类定义。不带TaskContinuationOptions参数,则无论前一个任务是如何结束的,后续任务都启动。也可以用TaskContinuationOptions枚举中的值,来指定连续任务在什么情况下启动。
static object o = new object();
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.Token.Register(()=>{
Console.WriteLine("*** token canceled.");
}); Task t1 = new Task(DoOnFirst, cts.Token);
//t1完成的情况下启动t2
Task t2 = t1.ContinueWith(DoOnSecond, TaskContinuationOptions.OnlyOnRanToCompletion);
//t1被取消的情况下启动t3
Task t3 = t1.ContinueWith(DoOnThird, TaskContinuationOptions.OnlyOnCanceled);
try
{
t1.Start();
//cts.Cancel( ); //打开注释,取消了t1,将执行DoOnThird。
}
catch
{
lib.print("t1.IsCanceled : " + t1.IsCanceled);
}
Console.ReadKey();
}
static void DoOnFirst()
{
lock (o)
{
lib.print("Task.CurrentId :" + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}
static void DoOnSecond(Task t)
{
lock (o)
{
lib.print("task " + t.Id + " finished.");
lib.print("this task id " + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}
static void DoOnThird(Task t)
{
lock (o)
{
lib.print("task " + t.Id + " Canceld.");
lib.print("this task id " + Task.CurrentId);
lib.print("-----------"); Thread.Sleep();
}
}
任务层次结构
任务也可以构成一个层次结构。一个任务启动一个新任务时,就启动了一个父/子层次结构。
任务的结果
任务结束时,可以把一些有用的状态信息写到共享对象中。也可以使用返回结果的任务返回这些信息。
static void Main(string[] args)
{
Task<int> t1 = new Task<int>((object o)=>{return ;}, "");
t1.Start();
t1.Wait();
lib.print(t1.Result); Task t = new Task(DoParentTask);
t.Start();
}
C# 多线程系列(四)
C# 多线程系列(三)的更多相关文章
- java多线程系列(三)---等待通知机制
等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...
- (Java多线程系列三)线程间通讯
Java多线程间通讯 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 1.使用wait()和notify()方法在线程中通讯 需求:第一个线程写入(input)用户,另一个线程 ...
- Java多线程系列三——实现线程同步的方法
两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...
- 【Java多线程系列三】实现线程同步的方法
两种实现线程同步的方法 方法 特性 synchronized 不需要显式的加锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...
- 多线程系列三:Lock和Condition
有了synchronized为什么还要Lock? 因为Lock和synchronized比较有如下优点 1. 尝试非阻塞地获取锁 2. 获取锁的过程可以被中断 3. 超时获取锁 Lock的标准用法 p ...
- Java多线程系列十——BlockingQueue
参考资料:http://ifeve.com/java-synchronousqueue/http://www.cnblogs.com/jackyuj/archive/2010/11/24/188655 ...
- Java多线程系列--“JUC线程池”04之 线程池原理(三)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...
- java 多线程系列---JUC原子类(三)之AtomicLongArray原子类
AtomicLongArray介绍和函数列表 在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
随机推荐
- Oracle 数据库连接的一些坑
问题: ORA-12504:TNS:监听程序在CONNECT_DATA中未获得SERVICE_NAMEORA-12514: TNS: 监听程序当前无法识别连接描述符中请求服务 解决办法: 1 权限 安 ...
- js 阻止冒泡事件和默认事件
阻止事件冒泡 window.enent ? window.enent.cancelBubble = true : e.stopPropagation() function stopBubble(eve ...
- 腾讯云,搭建LNMP环境
LNMP代表的就是:Linux系统下Nginx+MySQL+PHP这种网站服务器架构. Linux是一类Unix计算机操作系统的统称,是目前最流行的免费操作系统.代表版本有:debian.centos ...
- STM32窗口看门狗和独立看门狗的区别,看门狗介绍及代码演示
一.介绍: STM32看门狗分为独立看门狗和窗口看门狗两种,其两者使用调条件如下所示, IWDG和WWDG两者特点如下图所示: 独立看门狗的手册资料: 窗口看门狗的手册资料: ...
- padding填充与box-sizing: border-box配合使用
不管伸缩盒还是浮动盒子,只要使用到padding,就必须使用 box-sizing: border-box; 有图片的时候,需摇与其他文字对齐的时候,在图片的外层加个:vertical-ali ...
- Thawte
Thawte 公司为 VeriSign(即:现更名为Symantec) 全资子公司,是全球第三大数字证书颁发机构(CA),成立于1995年,自1996年正式提供数字证书产品到1999年占领全球市场的4 ...
- [bzoj3669][Noi2014]魔法森林_LCT_并查集
魔法森林 bzoj-3669 Noi-2014 题目大意:说不明白题意系列++……题目链接 注释:略. 想法:如果只有1个参量的话spfa.dij什么的都上来了. 两个参量的话我们考虑,想将所有的边按 ...
- spring boot.定时任务问题记录(TaskScheduler/ScheduledExecutorService异常)
一.背景 spring boot的定时任务非常简单,只需要在启动类中加上@EnableScheduling注解,然后在对应的方法上配置@Scheduled就可以了,系统会自动处理并按照Schedule ...
- python getaddrinfo 函数
现在python中用到的关于地址查询的函数几乎都可以用getaddrinfo. 也就是说,如果你要想做一些与地址查询,主机名ip转换的操作,都可以用这个函数,下面看一下这个函数. 首先,我们可以用ge ...
- (转)linux口令相关文件(/etc/passwd和/etc/shadow)
在linux中,口令文件在/etc/passwd中,早期的这个文件直接存放加密后的password,前两位是"盐"值,是一个随机数.后面跟的是加密的password.为了安全,如今 ...