更应该多留神I/O线程的操作,在进程入口实行的率先个线程被视为这几个历程的主线程

引言

一、线程的定义

正文首要从线程的基本作用法,CLRAV4线程池当湖南中华南理教院程公司笔者线程与I/O线程的开支,并行操作PLINQ等多少个地方介绍四线程的支付。
在这之中央委员托的BeginInvoke方法以及回调函数最为常用。 而
I/O线程恐怕轻易受到咱们的忽视,其实在开辟十六线程系统,更应有多留心I/O线程的操作。非常是在ASP.NET开荒在那之中,也许更多人只会小心在客商端应用Ajax或许在劳务器端使用UpdatePanel。其实言之有理利用I/O线程在简报项目或文件下载时,能尽量地压缩IIS的压力。
并行编制程序是Framework4.0中山学院力推广的异步操作形式,更值得越来越深入地球科学习。
希望本篇文章能对各位的读书钻研具备协理,个中有所错漏的地点敬请点评。

 1. 1 进度、应用程序域与线程的关系

 

经过(Process)是Windows系统中的两个基本概念,它包蕴着贰个运行程序所必要的资源。进程之间是相持独立的,贰个经过不可能访谈另二个经过的多寡(除非接纳布满式总计格局),多个历程运营的曲折也不会影响别的进度的运行,Windows系统正是接纳进度把专业划分为多少个单身的区域的。进程可以知道为二个前后相继的基本边界。

 

利用程序域(AppDomain)是四个程序运转的逻辑区域,它能够视为一个轻量级的进度,.NET的前后相继集正是在运用程序域中运转的,三个进度能够包涵有多少个利用程序域,四个使用程序域也可以富含八个程序集。在二个应用程序域中饱含了多个或七个左右文context,使用前后文CL福特Explorer就能够把一些特殊指标的情事放置在分歧容器当中。

目录

线程(Thread)是进度中的基本进行单元,在进程入口实践的率先个线程被视为这些进度的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此办法时系统就能够活动制造多少个主线程。线程首借使由CPU寄放器、调用栈和线程本地存储器(Thread
Local
Storage,TLS)组成的。CPU存放器重要记录当前所进行线程的事态,调用栈首要用来掩护线程所调用到的内存与数据,TLS首要用以寄存线程的状态消息。

一、线程的概念

经过、应用程序域、线程的涉嫌如下图,贰个进程内可以包蕴八个使用程序域,也许有囊括三个线程,线程也得以不停于七个利用程序域个中。但在同二个时刻,线程只会处在一个行使程序域内。

二、线程的基础知识

 

三、以ThreadStart情势实现二十多线程

图片 1

四、CL卡宴线程池的劳重力线程

 
鉴于本文是以介绍四线程技艺为主旨,对进度、应用程序域的牵线就到此截至。关于进程、线程、应用程序域的本事,在“C#汇总揭秘——细说过程、应用程序域与上下文”会有详细介绍。

五、CL兰德兰德酷路泽线程池的I/O线程

 

六、异步
SqlCommand

1.2 多线程

七、并行编制程序与PLINQ

在单CPU系统的二个单位时间(time
slice)内,CPU只可以运营单个线程,运转顺序取决于线程的预先等第。若是在单位时间内线程未能成功施行,系统就能把线程的情景音讯保存到线程的地头存储器(TLS)
中,以便后一次施行时上涨施行。而四线程只是系统带来的二个假像,它在七个单位时间内张开多个线程的切换。因为切换频密何况单位时间极短暂,所以多线程可被看成同期运营。

八、坚持计时器与锁

正好使用八线程能加强系统的习性,例如:在系统诉求大体积的数码时选用二十八线程,把数据输出专门的职业交给异步线程,使主线程保持其稳固去管理任何主题素材。但要求注意一点,因为CPU供给开支非常的多的年华在线程的切换上,所以重重地利用多线程反而会促成质量的下落。

 

 

 

归来目录

 

二、线程的基础知识

 

2.1 System.Threading.Thread类

一、线程的概念

System.Threading.Thread是用来调整线程的底子类,通过Thread能够操纵当前采纳程序域中线程的成立、挂起、截至、销毁。

 1. 1 进程、应用程序域与线程的关联

它回顾以下常用公共性质:

经过(Process)是Windows系统中的贰个基本概念,它包蕴着一个运作程序所须求的财富。进度之间是争辨独立的,三个历程无法访谈另八个进度的多寡(除非选择分布式总括方式),二个进度运转的败诉也不会耳濡目染其余进度的运作,Windows系统正是使用进程把专门的学问划分为三个单身的区域的。进度能够知道为三个程序的基本边界。

属性名称 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,该值指示线程的调度优先级。
ThreadState 获取一个值,该值包含当前线程的状态。

采纳程序域(AppDomain)是一个程序运营的逻辑区域,它能够算得三个轻量级的进度,.NET的顺序集正是在应用程序域中运维的,三个经过能够分包有多少个利用程序域,三个用到程序域也足以包罗七个程序集。在二个使用程序域中蕴涵了二个或多少个左右文context,使用前后文CL奥迪Q5就可见把一些特殊对象的情形放置在分化容器当中。

 

线程(Thread)是经过中的基本实行单元,在经过入口实施的首先个线程被视为这么些进度的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此措施时系统就能自行创制一个主线程。线程重若是由CPU寄存器、调用栈和线程本地存款和储蓄器(Thread
Local
Storage,TLS)组成的。CPU寄放器首要记录当前所实行线程的情事,调用栈首要用以保险线程所调用到的内部存款和储蓄器与数量,TLS主要用来存放线程的情状消息。

2.1.1 线程的标记符

过程、应用程序域、线程的涉嫌如下图,二个进程内得以包含八个应用程序域,也可能有囊括八个线程,线程也足以不停于四个使用程序域当中。但在同一个整天,线程只会处在贰个施用程序域内。

ManagedThreadId是承认线程的独一标志符,程序在超越五成情况下都以经过Thread.ManagedThreadId来分辨线程的。而Name是四个可变值,在暗中同意时候,Name为一个空值
Null,开辟职员能够由此程序设置线程的称号,但那只是四个扶助功效。

 

 

图片 2

2.1.2 线程的先行等级

 
由于本文是以介绍二十多线程技能为大旨,对经过、应用程序域的介绍就到此甘休。关于进度、线程、应用程序域的工夫,在“C#综合揭秘——细说进度、应用程序域与上下文”会有详细介绍。

.NET为线程设置了Priority属性来定义线程推行的先行等级,里面饱含5个选项,其中Normal是暗许值。除非系统有特殊须要,不然不应该随便设置线程的预先等级。

 

成员名称 说明
Lowest 可以将 Thread 安排在具有任何其他优先级的线程之后。
BelowNormal 可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。
Normal 默认选择。可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有BelowNormal 优先级的线程之前。
AboveNormal 可以将 Thread 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。
Highest 可以将 Thread 安排在具有任何其他优先级的线程之前。

1.2 多线程

 

在单CPU系统的二个单位时间(time
slice)内,CPU只可以运维单个线程,运营顺序取决于线程的事先等级。借使在单位时间内线程未能形成奉行,系统就能把线程的意况音讯保存到线程的地头存款和储蓄器(TLS)
中,以便下一次推行时上涨实行。而二十三十二线程只是系统带来的一个假像,它在多个单位时间内张开八个线程的切换。因为切换频密并且单位时间比相当短暂,所以四线程可被当做同时运维。

2.1.3 线程的气象

适合选择二十多线程能加强系统的性质,举例:在系统央浼大体量的数额时利用八线程,把数量输出专业付出异步线程,使主线程保持其安静去管理任何难点。但供给细心一点,因为CPU须求开支非常多的大运在线程的切换上,所以众多地选择二十八线程反而会产生质量的下落。

通过ThreadState能够检查测量试验线程是居于Unstarted、Sleeping、Running
等等状态,它比 IsAlive 属品质提供更加多的特定音讯。

 

前方说过,两个选拔程序域中只怕包涵八个上下文,而因此CurrentContext能够博得线程当前的上下文。

重临目录

CurrentThread是最常用的贰天性质,它是用来获取当前运作的线程。

二、线程的基础知识

 

2.1 System.Threading.Thread类

2.1.4 System.Threading.Thread的方法

System.Threading.Thread是用于调控线程的根底类,通过Thread能够调整当前采用程序域中线程的始建、挂起、截至、销毁。

Thread
中总结了多少个办法来支配线程的创造、挂起、截止、销毁,以往来的例子中会日常应用。

它回顾以下常用公共性质:

方法名称 说明
Abort()     终止本线程。
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start()   执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep()   把正在运行的线程挂起一段时间。
属性名称 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,该值指示线程的调度优先级。
ThreadState 获取一个值,该值包含当前线程的状态。

 

 

2.1.5 开辟实例

2.1.1 线程的标记符

以下那些例子,正是通过Thread显示当前线程音讯

ManagedThreadId是断定线程的唯一标志符,程序在大部情形下都以由此Thread.ManagedThreadId来辨别线程的。而Name是四个可变值,在暗中同意时候,Name为三个空值
Null,开拓人士能够经过程序设置线程的名称,但那只是二个赞助作用。

图片 3

 

 1         static void Main(string[] args)
 2         {
 3             Thread thread = Thread.CurrentThread;
 4             thread.Name = "Main Thread";
 5             string threadMessage = string.Format("Thread ID:{0}\n    Current AppDomainId:{1}\n    "+
 6                 "Current ContextId:{2}\n    Thread Name:{3}\n    "+
 7                 "Thread State:{4}\n    Thread Priority:{5}\n",
 8                 thread.ManagedThreadId, Thread.GetDomainID(), Thread.CurrentContext.ContextID,
 9                 thread.Name, thread.ThreadState, thread.Priority);
10             Console.WriteLine(threadMessage);
11             Console.ReadKey();
12         }

2.1.2 线程的初期品级

图片 4

.NET为线程设置了Priority属性来定义线程试行的优先等第,里面包蕴5个选项,当中Normal是暗中认可值。除非系统有特殊要求,不然不应当随意设置线程的先行等级。

 

成员名称 说明
Lowest 可以将 Thread 安排在具有任何其他优先级的线程之后。      
BelowNormal 可以将 Thread 安排在具有 Normal 优先级的线程之后,在具有 Lowest 优先级的线程之前。      
Normal 默认选择。可以将 Thread 安排在具有 AboveNormal 优先级的线程之后,在具有 BelowNormal 优先级的线程之前。 
AboveNormal 可以将 Thread 安排在具有 Highest 优先级的线程之后,在具有 Normal 优先级的线程之前。      
Highest 可以将 Thread 安排在具有任何其他优先级的线程之前。      

运行结果

 

图片 5

2.1.3 线程的景观

 

透过ThreadState能够检查测验线程是高居Unstarted、Sleeping、Running
等等状态,它比 IsAlive 属质量提供更多的特定音信。

2.2  System.Threading 命名空间

前方说过,二个使用程序域中或者包涵多个上下文,而由此CurrentContext能够拿走线程当前的上下文。

在System.Threading命名空间内提供五个艺术来创设多线程应用程序,在那之中ThreadPool与Thread是二十多线程开采中最常用到的,在.NET中极度设定了三个CLWrangler线程池特地用来管理线程的周转,那一个CL法拉利488线程池就是通过ThreadPool类来管理。而Thread是管制线程的最直白格局,上边几节将详细介绍有关内容。

CurrentThread是最常用的贰个性能,它是用以获取当前运作的线程。

类     说明
AutoResetEvent 通知正在等待的线程已发生事件。无法继承此类。
ExecutionContext 管理当前线程的执行上下文。无法继承此类。
Interlocked 为多个线程共享的变量提供原子操作。
Monitor 提供同步对对象的访问的机制。
Mutex 一个同步基元,也可用于进程间同步。
Thread 创建并控制线程,设置其优先级并获取其状态。
ThreadAbortException 在对 Abort 方法进行调用时引发的异常。无法继承此类。
ThreadPool 提供一个线程池,该线程池可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。
Timeout 包含用于指定无限长的时间的常数。无法继承此类。
Timer 提供以指定的时间间隔执行方法的机制。无法继承此类。
WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象。

 

在System.Threading中的包罗了下表中的多少个常用委托,当中ThreadStart、ParameterizedThreadStart是最常用到的寄托。
由ThreadStart生成的线程是最直白的秘技,但由ThreadStart所生成并不受线程池管理。
而ParameterizedThreadStart是为异步触发带参数的不二秘诀而设的,在下一节将为大家逐个细说。

2.1.4 System.Threading.Thread的方法

委托 说明
ContextCallback 表示要在新上下文中调用的方法。
ParameterizedThreadStart 表示在 Thread 上执行的方法。
ThreadExceptionEventHandler 表示将要处理 Application 的 ThreadException 事件的方法。
ThreadStart 表示在 Thread 上执行的方法。
TimerCallback 表示处理来自 Timer 的调用的方法。
WaitCallback 表示线程池线程要执行的回调方法。
WaitOrTimerCallback 表示当 WaitHandle 超时或终止时要调用的方法。

Thread
中归纳了多少个艺术来决定线程的始建、挂起、甘休、销毁,现在来的例证中会平时应用。

 

方法名称 说明
Abort()     终止本线程。
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start()   执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep()   把正在运行的线程挂起一段时间。

2.3 线程的田间管理章程

 

由此ThreadStart来创制二个新线程是最直白的主意,但那样成立出来的线程比较难管理,固然成立过多的线程反而会让系统的品质下载。有见及此,.NET为线程管理特别设置了多个CLPRADO线程池,使用CL揽胜线程池系统能够更合理地保管线程的使用。全数需要的劳动都能运作于线程池中,当运营甘休时线程便会回归到线程池。通过安装,能调节线程池的最大线程数量,在伸手越过线程最大值时,线程池能依照操作的预先品级来实行,让有些操作处于等候状态,待有线程回归时再试行操作。

2.1.5 开荒实例

基础知识就为大家介绍到那边,上边将详细介绍多线程的费用。

以下这一个例子,正是经过Thread彰显当前线程音信

 

图片 6😉

 

 1         static void Main(string[] args)
 2         {
 3             Thread thread = Thread.CurrentThread;
 4             thread.Name = "Main Thread";
 5             string threadMessage = string.Format("Thread ID:{0}\n    Current AppDomainId:{1}\n    "+
 6                 "Current ContextId:{2}\n    Thread Name:{3}\n    "+
 7                 "Thread State:{4}\n    Thread Priority:{5}\n",
 8                 thread.ManagedThreadId, Thread.GetDomainID(), Thread.CurrentContext.ContextID,
 9                 thread.Name, thread.ThreadState, thread.Priority);
10             Console.WriteLine(threadMessage);
11             Console.ReadKey();
12         }

重临目录

图片 7😉

三、以ThreadStart格局贯彻二十多线程

 

3.1 使用ThreadStart委托

运转结果

此间先以一个事例浮现一下四线程带来的收益,首先在Message类中创造贰个办法ShowMessage(),里面显示了当前运维线程的Id,并动用Thread.Sleep(int
)
方法模拟部分工作。在main()中通过ThreadStart委托绑定Message对象的ShowMessage()方法,然后经过Thread.Start()试行异步方法。

图片 8

图片 9

 

 1       public class Message
 2       {
 3           public void ShowMessage()
 4           {
 5               string message = string.Format("Async threadId is :{0}",
 6                                               Thread.CurrentThread.ManagedThreadId);
 7               Console.WriteLine(message);
 8   
 9               for (int n = 0; n < 10; n++)
10               {
11                   Thread.Sleep(300);   
12                   Console.WriteLine("The number is:" + n.ToString()); 
13               }
14           }
15       }
16   
17       class Program
18       {
19           static void Main(string[] args)
20           {
21               Console.WriteLine("Main threadId is:"+
22                                 Thread.CurrentThread.ManagedThreadId);
23               Message message=new Message();
24               Thread thread = new Thread(new ThreadStart(message.ShowMessage));
25               thread.Start();
26               Console.WriteLine("Do something ..........!");
27               Console.WriteLine("Main thread working is complete!");
28               
29           }
30       }

2.2  System.Threading 命名空间

图片 10

在System.Threading命名空间内提供四个法子来创设十二线程应用程序,当中ThreadPool与Thread是八线程开拓中最常用到的,在.NET中等职业高校门设定了一个CLTiggo线程池特地用来处理线程的运行,这些CL凯雷德线程池就是通过ThreadPool类来治本。而Thread是治本线程的最直白情势,上面几节将详细介绍有关内容。

请留心运维结果,在调用Thread.Start()方法后,系统以异步方式运营Message.ShowMessage(),而主线程的操作是继续试行的,在Message.ShowMessage()完结前,主线程已做到全部的操作。

类     说明
AutoResetEvent 通知正在等待的线程已发生事件。无法继承此类。
ExecutionContext 管理当前线程的执行上下文。无法继承此类。
Interlocked 为多个线程共享的变量提供原子操作。
Monitor 提供同步对对象的访问的机制。
Mutex 一个同步基元,也可用于进程间同步。
Thread 创建并控制线程,设置其优先级并获取其状态。
ThreadAbortException 在对 Abort 方法进行调用时引发的异常。无法继承此类。
ThreadPool 提供一个线程池,该线程池可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。
Timeout 包含用于指定无限长的时间的常数。无法继承此类。
Timer 提供以指定的时间间隔执行方法的机制。无法继承此类。
WaitHandle 封装等待对共享资源的独占访问的操作系统特定的对象。

图片 11

在System.Threading中的包罗了下表中的三个常用委托,个中ThreadStart、ParameterizedThreadStart是最常用到的嘱托。
由ThreadStart生成的线程是最间接的主意,但由ThreadStart所生成并不受线程池管理。
而ParameterizedThreadStart是为异步触发带参数的章程而设的,在下一节将为大家逐条细说。

 

委托 说明
ContextCallback 表示要在新上下文中调用的方法。
ParameterizedThreadStart 表示在 Thread 上执行的方法。
ThreadExceptionEventHandler 表示将要处理 Application 的 ThreadException 事件的方法。
ThreadStart 表示在 Thread 上执行的方法。
TimerCallback 表示处理来自 Timer 的调用的方法。
WaitCallback 表示线程池线程要执行的回调方法。
WaitOrTimerCallback 表示当 WaitHandle 超时或终止时要调用的方法。

3.2 使用ParameterizedThreadStart委托

 

ParameterizedThreadStart委托与ThreadStart委托非常相似,但ParameterizedThreadStart委托是面向带参数方法的。注意ParameterizedThreadStart
对应措施的参数为object,此参数可感觉三个值对象,也可感觉三个自定义对象。

2.3 线程的管理方法

图片 12

由此ThreadStart来创制一个新线程是最直接的主意,但那样创造出来的线程比较难处理,要是创设过多的线程反而会让系统的性格下载。有见及此,.NET为线程管理特地设置了三个CLOdyssey线程池,使用CL奥德赛线程池系统能够更合理地保管线程的应用。全部乞求的服务都能运行于线程池中,当运维甘休时线程便会回归到线程池。通过设置,能调整线程池的最大线程数量,在呼吁超越线程最大值时,线程池能依照操作的优先品级来实行,让有些操作处于等候情形,待有线程回归时再实施操作。

 1     public class Person
 2     {
 3         public string Name
 4         {
 5             get;
 6             set;
 7         }
 8         public int Age
 9         {
10             get;
11             set;
12         }
13     }
14 
15     public class Message
16     {
17         public void ShowMessage(object person)
18         {
19             if (person != null)
20             {
21                 Person _person = (Person)person;
22                 string message = string.Format("\n{0}'s age is {1}!\nAsync threadId is:{2}",
23                     _person.Name,_person.Age,Thread.CurrentThread.ManagedThreadId);
24                 Console.WriteLine(message);
25             }
26             for (int n = 0; n < 10; n++)
27             {
28                 Thread.Sleep(300);   
29                 Console.WriteLine("The number is:" + n.ToString()); 
30             }
31         }
32     }
33 
34     class Program
35     {
36         static void Main(string[] args)
37         {     
38             Console.WriteLine("Main threadId is:"+Thread.CurrentThread.ManagedThreadId);
39             
40             Message message=new Message();
41             //绑定带参数的异步方法
42             Thread thread = new Thread(new ParameterizedThreadStart(message.ShowMessage));
43             Person person = new Person();
44             person.Name = "Jack";
45             person.Age = 21;
46             thread.Start(person);  //启动异步线程 
47             
48             Console.WriteLine("Do something ..........!");
49             Console.WriteLine("Main thread working is complete!");
50              
51         }
52     }

基础知识就为大家介绍到这里,上边将详细介绍十二线程的支出。

图片 13

 

运行结果:

 

图片 14

再次回到目录

 

三、以ThreadStart格局完结八线程

3.3 前台线程与后台线程

3.1 使用ThreadStart委托

留心上述三个例证都并未有应用Console.ReadKey(),但系统照旧会等待异步线程完结后才会终结。这是因为运用Thread.Start()运营的线程默以为前台线程,而系统必须等待全数前台线程运营甘休后,应用程序域才会自行卸载。

此处先以一个例证显示一下多线程带来的益处,首先在Message类中国建工业总会公司立八个办法ShowMessage(),里面突显了眼下运作线程的Id,并动用Thread.Sleep(int
)
方法模拟部分职业。在main()中经过ThreadStart委托绑定Message对象的ShowMessage()方法,然后通过Thread.Start()推行异步方法。

在第一节曾经介绍过线程Thread有贰性情能IsBackground,通过把此属性设置为true,就能够把线程设置为后台线程!那时应用程序域就要主线程完成时就被卸载,而不会等待异步线程的运作。

图片 15😉

 

 1       public class Message  2       {  3           public void ShowMessage()  4           {  5               string message = string.Format("Async threadId is :{0}",  6                                               Thread.CurrentThread.ManagedThreadId);  7               Console.WriteLine(message);  8     9               for (int n = 0; n < 10; n++) 10               { 11                   Thread.Sleep(300);    12                   Console.WriteLine("The number is:" + n.ToString());  13               } 14           } 15       } 16    17       class Program 18       { 19           static void Main(string[] args) 20           { 21               Console.WriteLine("Main threadId is:"+ 22                                 Thread.CurrentThread.ManagedThreadId); 23               Message message=new Message(); 24               Thread thread = new Thread(new ThreadStart(message.ShowMessage)); 25               thread.Start(); 26               Console.WriteLine("Do something ..........!"); 27               Console.WriteLine("Main thread working is complete!"); 28                29           } 30       }

3.4 挂起线程

图片 16😉

为了等待其余后台线程完毕后再甘休主线程,就能够使用Thread.Sleep()方法。

请留神运行结果,在调用Thread.Start()方法后,系统以异步情势运维Message.ShowMessage(),而主线程的操作是继续施行的,在Message.ShowMessage()完毕前,主线程已成功具有的操作。

图片 17

图片 18

 1     public class Message
 2     {
 3         public void ShowMessage()
 4         {
 5             string message = string.Format("\nAsync threadId is:{0}",
 6                                            Thread.CurrentThread.ManagedThreadId);
 7             Console.WriteLine(message);
 8             for (int n = 0; n < 10; n++)
 9             {
10                 Thread.Sleep(300);
11                 Console.WriteLine("The number is:" + n.ToString());
12             }
13         }
14     }
15 
16     class Program
17     {
18         static void Main(string[] args)
19         {     
20             Console.WriteLine("Main threadId is:"+
21                               Thread.CurrentThread.ManagedThreadId);
22             
23             Message message=new Message();
24             Thread thread = new Thread(new ThreadStart(message.ShowMessage));
25             thread.IsBackground = true;
26             thread.Start();
27             
28             Console.WriteLine("Do something ..........!");
29             Console.WriteLine("Main thread working is complete!");
30             Console.WriteLine("Main thread sleep!");
31             Thread.Sleep(5000);
32         }
33     }

 

图片 19

3.2 使用ParameterizedThreadStart委托

运作结果如下,此时选取程序域就要主线程运转5秒后活动终止

ParameterizedThreadStart委托与ThreadStart委托特别相似,但ParameterizedThreadStart委托是面向带参数方法的。注意ParameterizedThreadStart
对应措施的参数为object,此参数可以为贰个值对象,也得以为二个自定义对象。

图片 20

图片 21😉

 

 1     public class Person
 2     {
 3         public string Name
 4         {
 5             get;
 6             set;
 7         }
 8         public int Age
 9         {
10             get;
11             set;
12         }
13     }
14 
15     public class Message
16     {
17         public void ShowMessage(object person)
18         {
19             if (person != null)
20             {
21                 Person _person = (Person)person;
22                 string message = string.Format("\n{0}'s age is {1}!\nAsync threadId is:{2}",
23                     _person.Name,_person.Age,Thread.CurrentThread.ManagedThreadId);
24                 Console.WriteLine(message);
25             }
26             for (int n = 0; n < 10; n++)
27             {
28                 Thread.Sleep(300);   
29                 Console.WriteLine("The number is:" + n.ToString()); 
30             }
31         }
32     }
33 
34     class Program
35     {
36         static void Main(string[] args)
37         {     
38             Console.WriteLine("Main threadId is:"+Thread.CurrentThread.ManagedThreadId);
39             
40             Message message=new Message();
41             //绑定带参数的异步方法
42             Thread thread = new Thread(new ParameterizedThreadStart(message.ShowMessage));
43             Person person = new Person();
44             person.Name = "Jack";
45             person.Age = 21;
46             thread.Start(person);  //启动异步线程 
47             
48             Console.WriteLine("Do something ..........!");
49             Console.WriteLine("Main thread working is complete!");
50              
51         }
52     }

但系统无法预感异步线程须要周转的光阴,所以用经过Thread.Sleep(int)阻塞主线程实际不是二个好的减轻措施。有见及此,.NET特意为等候异步线程实现开垦了另四个措施thread.Join()。把上边例子中的最后一行Thread.Sleep(5000)修改为
thread.Join() 就能够担保主线程在异步线程thread运维结束后才会停下。

图片 22😉

 

运转结果:

3.5 Suspend 与 Resume (慎用)

图片 23

Thread.Suspend()与 Thread.Resume()是在Framework1.0
就早就存在的老艺术了,它们各自可以挂起、复苏线程。但在Framework2.0中就曾经人人皆知排斥那多少个艺术。那是因为尽管有些线程占用了已有的能源,再使用Suspend()使线程短时间居于挂起状态,当在别的线程调用那些财富的时候就能引起死锁!所以在未曾供给的情况下应该防止使用那三个点子。

 

 

3.3 前台线程与后台线程

3.6 终止线程

潜心上述三个例子都不曾动用Console.ReadKey(),但系统依旧会等待异步线程达成后才会截止。那是因为使用Thread.Start()运行的线程默以为前台线程,而系统必得等待全数前台线程运营截止后,应用程序域才会自动卸载。

若想终止正在周转的线程,可以选择Abort()方法。在使用Abort()的时候,将抓住二个特有格外ThreadAbortException 。
若想在线程终止前苏醒线程的施行,能够在破获至极后
,在catch(ThreadAbortException ex){…}
中调用Thread.ResetAbort()取消终止。
而利用Thread.Join()能够有限支撑应用程序域等待异步线程结束后才打住运营。

在第2节曾经介绍过线程Thread有贰本质量IsBackground,通过把此属性设置为true,就能够把线程设置为后台线程!这时应用程序域将要主线程完结时就被卸载,而不会等待异步线程的运作。

图片 24

 

 1          static void Main(string[] args)
 2          {
 3              Console.WriteLine("Main threadId is:" +
 4                                Thread.CurrentThread.ManagedThreadId);
 5  
 6              Thread thread = new Thread(new ThreadStart(AsyncThread));
 7              thread.IsBackground = true;
 8              thread.Start();
 9              thread.Join();
10  
11          }     
12          
13          //以异步方式调用
14          static void AsyncThread()
15          {
16              try
17              {
18                  string message = string.Format("\nAsync threadId is:{0}",
19                     Thread.CurrentThread.ManagedThreadId);
20                  Console.WriteLine(message);
21  
22                  for (int n = 0; n < 10; n++)
23                  {
24                      //当n等于4时,终止线程
25                      if (n >= 4)
26                      {
27                          Thread.CurrentThread.Abort(n);
28                      }
29                      Thread.Sleep(300);
30                      Console.WriteLine("The number is:" + n.ToString());
31                  }
32              }
33              catch (ThreadAbortException ex)
34              {
35                  //输出终止线程时n的值
36                  if (ex.ExceptionState != null)
37                      Console.WriteLine(string.Format("Thread abort when the number is: {0}!", 
38                                                       ex.ExceptionState.ToString()));
39                 
40                  //取消终止,继续执行线程
41                  Thread.ResetAbort();
42                  Console.WriteLine("Thread ResetAbort!");
43              }
44  
45              //线程结束
46              Console.WriteLine("Thread Close!");
47          }

3.4 挂起线程

图片 25

为了等待别的后台线程达成后再结束主线程,就能够应用Thread.Sleep()方法。

运作结果如下

图片 26😉

图片 27

 1     public class Message  2     {  3         public void ShowMessage()  4         {  5             string message = string.Format("\nAsync threadId is:{0}",  6                                            Thread.CurrentThread.ManagedThreadId);  7             Console.WriteLine(message);  8             for (int n = 0; n < 10; n++)  9             { 10                 Thread.Sleep(300); 11                 Console.WriteLine("The number is:" + n.ToString()); 12             } 13         } 14     } 15  16     class Program 17     { 18         static void Main(string[] args) 19         {      20             Console.WriteLine("Main threadId is:"+ 21                               Thread.CurrentThread.ManagedThreadId); 22              23             Message message=new Message(); 24             Thread thread = new Thread(new ThreadStart(message.ShowMessage)); 25             thread.IsBackground = true; 26             thread.Start(); 27              28             Console.WriteLine("Do something ..........!"); 29             Console.WriteLine("Main thread working is complete!"); 30             Console.WriteLine("Main thread sleep!"); 31             Thread.Sleep(5000); 32         } 33     }

 

图片 28😉

 

运营结果如下,此时利用程序域将要主线程运转5秒后自动终止

回到目录

图片 29

四、CLPRADO线程池的劳力线程

 

4.1 关于CLR线程池

但系统不能够预感异步线程须求周转的时间,所以用经过Thread.Sleep(int)阻塞主线程并不是二个好的缓慢解决措施。有见及此,.NET特地为等待异步线程完毕开采了另多少个措施thread.Join()。把上边例子中的最终一行Thread.Sleep(6000)修改为
thread.Join() 就能够担保主线程在异步线程thread运维结束后才会停下。

接纳ThreadStart与ParameterizedThreadStart创建新线程非常轻松,但由此此方法成立的线程难于管理,若创建过多的线程反而会耳濡目染系统的性质。
有见及此,.NET引进CLXC90线程池那个概念。CLEnclave线程池并不会在CLENCORE初阶化的时候立时创制线程,而是在应用程序要创建线程来进行职务时,线程池才初步化贰个线程。线程的伊始化与另外的线程同样。在成就职责之后,该线程不会活动销毁,而是以挂起的事态再次来到到线程池。直到应用程序再一次向线程池发出必要时,线程池里挂起的线程就能够重复激活推行任务。那样既节约了创立线程所形成的习性损耗,也足以让几个任务每每重用同一线程,进而在应用程序生存期内节约大批量支出。

 

注意通过CL奥迪Q5线程池所建构的线程总是默认为后台线程,优先级数为ThreadPriority.Normal。

3.5 Suspend 与 Resume (慎用)

 

Thread.Suspend()与 Thread.Resume()是在Framework1.0
就早已存在的老艺术了,它们各自能够挂起、恢复生机线程。但在Framework2.0中就曾经人人皆知排斥那多少个办法。那是因为只要有些线程占用了已部分财富,再使用Suspend()使线程长期居于挂起状态,当在别的线程调用这几个财富的时候就能够挑起死锁!所以在尚未供给的意况下应该避免使用那七个艺术。

4.2 工小编线程与I/O线程

 

CLPRADO线程池分为工我线程(workerThreads)与I/O线程 (completionPortThreads)
三种,工小编线程是非常重要用作管理CL卡宴内部对象的运作,I/O(Input/Output)
线程以管窥天是用于与表面系统沟通消息,IO线程的细节就要下一节详细表明。

3.6 终止线程

由此ThreadPool.Get马克斯(out int workerThreads,out int
completionPortThreads )和 ThreadPool.Set马克斯( int workerThreads, int
completionPortThreads)五个方法能够独家读取和装置CLENVISION线程池山西中华南理艺术大学程公司小编线程与I/O线程的最大线程数。在Framework2.0中最大线程默感到25*CPU数,在Framewok3.0、4.0中最大线程数私下认可为250*CPU数,在眼前I3,I5,I7 CPU出现后,线程池的最大值一般默感到一千、三千。
若想测验线程池中有多少的线程正在投入使用,能够由此ThreadPool.GetAvailableThreads( out
int workerThreads,out int completionPortThreads ) 方法。

若想终止正在运作的线程,能够动用Abort()方法。在动用Abort()的时候,将引发八个特种格外ThreadAbortException 。 若想在线程终止前苏醒线程的实施,能够在破获分外后
,在catch(ThreadAbortException ex){…}
中调用Thread.ResetAbort()撤消终止。
而使用Thread.Join()能够确定保障应用程序域等待异步线程甘休后才停息运行。

使用CLLacrosse线程池的工小编线程一般有二种办法,一是平昔通过
ThreadPool.QueueUserWorkItem() 方法,二是透过委托,下边将依次细说。

图片 30😉

 

 1          static void Main(string[] args)
 2          {
 3              Console.WriteLine("Main threadId is:" +
 4                                Thread.CurrentThread.ManagedThreadId);
 5  
 6              Thread thread = new Thread(new ThreadStart(AsyncThread));
 7              thread.IsBackground = true;
 8              thread.Start();
 9              thread.Join();
10  
11          }     
12          
13          //以异步方式调用
14          static void AsyncThread()
15          {
16              try
17              {
18                  string message = string.Format("\nAsync threadId is:{0}",
19                     Thread.CurrentThread.ManagedThreadId);
20                  Console.WriteLine(message);
21  
22                  for (int n = 0; n < 10; n++)
23                  {
24                      //当n等于4时,终止线程
25                      if (n >= 4)
26                      {
27                          Thread.CurrentThread.Abort(n);
28                      }
29                      Thread.Sleep(300);
30                      Console.WriteLine("The number is:" + n.ToString());
31                  }
32              }
33              catch (ThreadAbortException ex)
34              {
35                  //输出终止线程时n的值
36                  if (ex.ExceptionState != null)
37                      Console.WriteLine(string.Format("Thread abort when the number is: {0}!", 
38                                                       ex.ExceptionState.ToString()));
39                 
40                  //取消终止,继续执行线程
41                  Thread.ResetAbort();
42                  Console.WriteLine("Thread ResetAbort!");
43              }
44  
45              //线程结束
46              Console.WriteLine("Thread Close!");
47          }

4.3 通过QueueUserWorkItem运营工我线程

图片 31😉

ThreadPool线程池中包括有多个静态方法可以直接开行工小编线程:
一为 ThreadPool.QueueUserWorkItem(WaitCallback)
二为 ThreadPool.QueueUserWorkItem(WaitCallback,Object) 

运维结果如下

先把WaitCallback委托指向三个带有Object参数的无重临值方法,再接纳ThreadPool.QueueUserWorkItem(WaitCallback)
就足以异步运维此方法,此时异步方法的参数被视为null 。

图片 32

图片 33

 

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //把CLR线程池的最大值设置为1000
 6             ThreadPool.SetMaxThreads(1000, 1000);
 7             //显示主线程启动时线程池信息
 8             ThreadMessage("Start");
 9             //启动工作者线程
10             ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback));
11             Console.ReadKey();
12         }
13         
14         static void AsyncCallback(object state)
15         {
16             Thread.Sleep(200);
17             ThreadMessage("AsyncCallback");
18             Console.WriteLine("Async thread do work!");
19         }
20 
21         //显示线程现状
22         static void ThreadMessage(string data)
23         {
24             string message = string.Format("{0}\n  CurrentThreadId is {1}",
25                  data, Thread.CurrentThread.ManagedThreadId);
26             Console.WriteLine(message);
27         }
28     }

 

图片 34

再次来到目录

运作结果

四、CL凯雷德线程池的劳引力线程

图片 35

4.1 关于CLR线程池

 

动用ThreadStart与ParameterizedThreadStart创立新线程特别轻便,但由此此方式创制的线程难于管理,若建设构造过多的线程反而会潜移暗化系统的质量。
有见及此,.NET引进CL纳瓦拉线程池那些定义。CLTiggo线程池并不会在CL凯雷德最初化的时候即刻创立线程,而是在应用程序要创设线程来试行任务时,线程池才初步化一个线程。线程的伊始化与别的的线程同样。在形成职分之后,该线程不会活动销毁,而是以挂起的场合再次来到到线程池。直到应用程序再一次向线程池发出央求时,线程池里挂起的线程就能再一次激活推行职分。那样既节约了创建线程所变成的属性损耗,也足以让多个任务一再重用同一线程,进而在应用程序生存期内节约多量开拓。

应用 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
方法能够把object对象作为参数字传送送到回调函数中。
下边例子中正是把一个string对象作为参数发送到回调函数个中。

注意经过CLSportage线程池所树立的线程总是默以为后台线程,优先级数为ThreadPriority.Normal。

图片 36

 

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //把线程池的最大值设置为1000
 6             ThreadPool.SetMaxThreads(1000, 1000);
 7           
 8             ThreadMessage("Start");
 9             ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback),"Hello Elva");
10             Console.ReadKey();
11         }
12 
13         static void AsyncCallback(object state)
14         {
15             Thread.Sleep(200);
16             ThreadMessage("AsyncCallback");
17 
18             string data = (string)state;
19             Console.WriteLine("Async thread do work!\n"+data);
20         }
21 
22         //显示线程现状
23         static void ThreadMessage(string data)
24         {
25             string message = string.Format("{0}\n  CurrentThreadId is {1}",
26                  data, Thread.CurrentThread.ManagedThreadId);
27             Console.WriteLine(message);
28         }
29     }

4.2 工作者线程与I/O线程

图片 37

CLENVISION线程池分为工小编线程(workerThreads)与I/O线程 (completionPortThreads)
二种,工小编线程是器重用作管理CL福睿斯内部对象的运作,I/O(Input/Output)
线程看名称就能够想到其意义是用于与表面系统交流音信,IO线程的细节就要下一节详细表达。

运维结果

由此ThreadPool.Get马克斯(out int workerThreads,out int
completionPortThreads )和 ThreadPool.Set马克斯( int workerThreads, int
completionPortThreads)四个方法可以独家读取和装置CL福特Explorer线程池福建中华南理工科业余大学学学程集团小编线程与I/O线程的最大线程数。在Framework2.0中最大线程默感到25*CPU数,在Framewok3.0、4.0中最大线程数默感觉250*CPU数,在近来I3,I5,I7 CPU出现后,线程池的最大值一般默以为一千、三千。
若想测量试验线程池中有稍许的线程正在投入使用,可以经过ThreadPool.GetAvailableThreads(
out int workerThreads,out int
completionPortThreads ) 方法。

图片 38

行使CLOdyssey线程池的劳力线程一般有三种艺术,一是从来通过
ThreadPool.QueueUserWorkItem() 方法,二是由此委托,上边将相继细说。

 

 

经过ThreadPool.QueueUserWorkItem运营工作者线程尽管是有益,但WaitCallback委托指向的必得是多个蕴含Object参数的无重回值方法,那如实是一种限制。若方法供给有重回值,恐怕隐含多少个参数,这将多费周折。有见及此,.NET提供了另一种形式去创设工小编线程,那就是寄托。

4.3 通过QueueUserWorkItem运营工作者线程

 

ThreadPool线程池中含有有八个静态方法能够向来开发银行工作者线程: 一为
ThreadPool.QueueUserWorkItem(WaitCallback) 二为
ThreadPool.QueueUserWorkItem(WaitCallback,Object) 

4.4  委托类       

先把WaitCallback委托指向叁个满含Object参数的无再次回到值方法,再使用
ThreadPool.QueueUserWorkItem(WaitCallback)
就能够异步运行此措施,此时异步方法的参数被视为null 。

动用CLRubicon线程池中的工笔者线程,最灵敏最常用的方法就是使用委托的异步方法,在此先简要介绍一下委托类。

图片 39😉

当定义委托后,.NET就能自动创制三个意味该信托的类,下边能够用反射方式体现委托类的艺术成员(对反射风野趣的仇人能够先参照他事他说加以考察一下“.NET基础篇——反射的神秘”)

 1     class Program  2     {  3         static void Main(string[] args)  4         {  5             //把CLR线程池的最大值设置为1000  6             ThreadPool.SetMaxThreads(1000, 1000);  7             //显示主线程启动时线程池信息  8             ThreadMessage("Start");  9             //启动工作者线程 10             ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback)); 11             Console.ReadKey(); 12         } 13          14         static void AsyncCallback(object state) 15         { 16             Thread.Sleep(200); 17             ThreadMessage("AsyncCallback"); 18             Console.WriteLine("Async thread do work!"); 19         } 20  21         //显示线程现状 22         static void ThreadMessage(string data) 23         { 24             string message = string.Format("{0}\n  CurrentThreadId is {1}", 25                  data, Thread.CurrentThread.ManagedThreadId); 26             Console.WriteLine(message); 27         } 28     }

图片 40

图片 41😉

 1     class Program
 2     {
 3         delegate void MyDelegate();
 4 
 5         static void Main(string[] args)
 6         {
 7             MyDelegate delegate1 = new MyDelegate(AsyncThread);
 8             //显示委托类的几个方法成员     
 9             var methods=delegate1.GetType().GetMethods();
10             if (methods != null)
11                 foreach (MethodInfo info in methods)
12                     Console.WriteLine(info.Name);
13             Console.ReadKey();
14          }
15      }

运作结果

图片 42

图片 43

委托类包罗以下多少个基本点方式

 

图片 44

利用 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
方法能够把object对象作为参数字传送送到回调函数中。
上边例子中正是把一个string对象作为参数发送到回调函数在那之中。

图片 45

图片 46😉

1     public class MyDelegate:MulticastDelegate
2     {
3         public MyDelegate(object target, int methodPtr);
4         //调用委托方法
5         public virtual void Invoke();
6         //异步委托
7         public virtual IAsyncResult BeginInvoke(AsyncCallback callback,object state);
8         public virtual void EndInvoke(IAsyncResult result);
9     }
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //把线程池的最大值设置为1000
 6             ThreadPool.SetMaxThreads(1000, 1000);
 7           
 8             ThreadMessage("Start");
 9             ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncCallback),"Hello Elva");
10             Console.ReadKey();
11         }
12 
13         static void AsyncCallback(object state)
14         {
15             Thread.Sleep(200);
16             ThreadMessage("AsyncCallback");
17 
18             string data = (string)state;
19             Console.WriteLine("Async thread do work!\n"+data);
20         }
21 
22         //显示线程现状
23         static void ThreadMessage(string data)
24         {
25             string message = string.Format("{0}\n  CurrentThreadId is {1}",
26                  data, Thread.CurrentThread.ManagedThreadId);
27             Console.WriteLine(message);
28         }
29     }

图片 47

图片 48😉

当调用Invoke()方法时,对应此委托的具有办法都会被实行。而BeginInvoke与EndInvoke则扶助委托方法的异步调用,由BeginInvoke运营的线程都属于CL汉兰达线程池中的工小编线程,在底下将详细表达。

运行结果

 

图片 49

4.5  利用BeginInvoke与EndInvoke实现异步委托方法

 

先是成立三个信托对象,通过IAsyncResult BeginInvoke(string
name,AsyncCallback callback,object state) 异步调用委托方法,BeginInvoke
方法除最终的八个参数外,另外参数都以与办法参数相呼应的。通过 BeginInvoke
方法将回到一个落实了 System.IAsyncResult
接口的靶子,之后就可以运用EndInvoke(IAsyncResult )
方法就足以了结异步操作,获取委托的运营结果。

通过ThreadPool.QueueUserWorkItem运转工小编线程即便是低价,但WaitCallback委托指向的总得是三个包括Object参数的无重返值方法,那如实是一种限制。若方法须求有重临值,或然隐含三个参数,这将多费周折。有见及此,.NET提供了另一种办法去建构工作者线程,那正是信托。

图片 50

 

 1     class Program
 2     {
 3         delegate string MyDelegate(string name);
 4 
 5         static void Main(string[] args)
 6         {
 7             ThreadMessage("Main Thread");
 8             
 9             //建立委托
10             MyDelegate myDelegate = new MyDelegate(Hello);
11             //异步调用委托,获取计算结果
12             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null);
13             //完成主线程其他工作
14             ............. 
15             //等待异步方法完成,调用EndInvoke(IAsyncResult)获取运行结果
16             string data=myDelegate.EndInvoke(result);
17             Console.WriteLine(data);
18             
19             Console.ReadKey();
20         }
21 
22         static string Hello(string name)
23         {
24             ThreadMessage("Async Thread");
25             Thread.Sleep(2000);            //虚拟异步工作
26             return "Hello " + name;
27         }
28 
29         //显示当前线程
30         static void ThreadMessage(string data)
31         {
32             string message = string.Format("{0}\n  ThreadId is:{1}",
33                    data,Thread.CurrentThread.ManagedThreadId);
34             Console.WriteLine(message);
35         }
36     }

4.4  委托类       

图片 51

动用CLEscort线程池中的工笔者线程,最灵敏最常用的不二等秘书诀正是使用委托的异步方法,在此先简要介绍一下委托类。

运转结果

当定义委托后,.NET就能自行创立四个意味该信托的类,上边能够用反射方式显示委托类的措施成员(对反射风野趣的意中人能够先参谋一下“.NET基础篇——反射的奥秘”)

图片 52

图片 53😉

 

 1     class Program  2     {  3         delegate void MyDelegate();  4   5         static void Main(string[] args)  6         {  7             MyDelegate delegate1 = new MyDelegate(AsyncThread);  8             //显示委托类的几个方法成员       9             var methods=delegate1.GetType().GetMethods(); 10             if (methods != null) 11                 foreach (MethodInfo info in methods) 12                     Console.WriteLine(info.Name); 13             Console.ReadKey(); 14          } 15      }

4.6  善用IAsyncResult

图片 54😉

在上述例子中得以望见,要是在应用myDelegate.BeginInvoke后即时调用myDelegate.EndInvoke,那在异步线程未造成专门的学问在此以前主线程将处于阻塞状态,等到异步线程甘休获取计算结果后,主线程手艺承接做事,那显然无可奈何体现出二十四线程的优势。此时能够优秀利用IAsyncResult
提高主线程的专门的学问性质,IAsyncResult有以下成员:

委托类包罗以下多少个根本格局

图片 55

图片 56

1 public interface IAsyncResult
2 {
3     object AsyncState {get;}            //获取用户定义的对象,它限定或包含关于异步操作的信息。
4     WailHandle AsyncWaitHandle {get;}   //获取用于等待异步操作完成的 WaitHandle。
5     bool CompletedSynchronously {get;}  //获取异步操作是否同步完成的指示。
6     bool IsCompleted {get;}             //获取异步操作是否已完成的指示。
7 }

图片 57😉

图片 58

1     public class MyDelegate:MulticastDelegate
2     {
3         public MyDelegate(object target, int methodPtr);
4         //调用委托方法
5         public virtual void Invoke();
6         //异步委托
7         public virtual IAsyncResult BeginInvoke(AsyncCallback callback,object state);
8         public virtual void EndInvoke(IAsyncResult result);
9     }

透过轮询格局,使用IsCompleted属性决断异步操作是还是不是做到,这样在异步操作未到位前就可以让主线程实践另外的干活。

图片 59😉

图片 60

当调用Invoke()方法时,对应此委托的装有办法都会被实践。而BeginInvoke与EndInvoke则帮助委托方法的异步调用,由BeginInvoke运维的线程都属于CL本田CR-V线程池中的工笔者线程,在上面将详细表明。

 1     class Program
 2     {
 3         delegate string MyDelegate(string name);
 4 
 5         static void Main(string[] args)
 6         {
 7             ThreadMessage("Main Thread");
 8             
 9             //建立委托
10             MyDelegate myDelegate = new MyDelegate(Hello);
11             //异步调用委托,获取计算结果
12             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null);
13             //在异步线程未完成前执行其他工作
14             while (!result.IsCompleted)
15             {
16                 Thread.Sleep(200);      //虚拟操作
17                 Console.WriteLine("Main thead do work!");
18             }
19             string data=myDelegate.EndInvoke(result);
20             Console.WriteLine(data);
21             
22             Console.ReadKey();
23         }
24 
25         static string Hello(string name)
26         {
27             ThreadMessage("Async Thread");
28             Thread.Sleep(2000);
29             return "Hello " + name;
30         }
31 
32         static void ThreadMessage(string data)
33         {
34             string message = string.Format("{0}\n  ThreadId is:{1}",
35                    data,Thread.CurrentThread.ManagedThreadId);
36             Console.WriteLine(message);
37         }
38     }

 

图片 61

4.5  利用BeginInvoke与EndInvoke完毕异步委托方法

运营结果:

先是创建一个寄托对象,通过IAsyncResult BeginInvoke(string
name,AsyncCallback callback,object state) 异步调用委托方法,BeginInvoke
方法除最后的多个参数外,别的参数都以与措施参数相呼应的。通过 BeginInvoke
方法将回到二个得以实现了 System.IAsyncResult
接口的对象,之后即可使用EndInvoke(IAsyncResult )
方法就能够终结异步操作,获取委托的运转结果。

图片 62

图片 63😉

 

 1     class Program  2     {  3         delegate string MyDelegate(string name);  4   5         static void Main(string[] args)  6         {  7             ThreadMessage("Main Thread");  8               9             //建立委托 10             MyDelegate myDelegate = new MyDelegate(Hello); 11             //异步调用委托,获取计算结果 12             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null); 13             //完成主线程其他工作 14             .............  15             //等待异步方法完成,调用EndInvoke(IAsyncResult)获取运行结果 16             string data=myDelegate.EndInvoke(result); 17             Console.WriteLine(data); 18              19             Console.ReadKey(); 20         } 21  22         static string Hello(string name) 23         { 24             ThreadMessage("Async Thread"); 25             Thread.Sleep(2000);            //虚拟异步工作 26             return "Hello " + name; 27         } 28  29         //显示当前线程 30         static void ThreadMessage(string data) 31         { 32             string message = string.Format("{0}\n  ThreadId is:{1}", 33                    data,Thread.CurrentThread.ManagedThreadId); 34             Console.WriteLine(message); 35         } 36     }

除此以外,也足以使用WailHandle实现一样的工作,WaitHandle里面含有有三个办法WaitOne(int
timeout),它能够看清委托是不是做到职业,在干活未成功前主线程可以继续其余干活。运维上面代码可获得与应用
IAsyncResult.IsCompleted 同样的结果,何况更简便易行方便 。

图片 64😉

图片 65

运作结果

 1 namespace Test
 2 {
 3     class Program
 4     {
 5         delegate string MyDelegate(string name);
 6 
 7         static void Main(string[] args)
 8         {
 9             ThreadMessage("Main Thread");
10             
11             //建立委托
12             MyDelegate myDelegate = new MyDelegate(Hello);
13  
14             //异步调用委托,获取计算结果
15             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null);
16             
17             while (!result.AsyncWaitHandle.WaitOne(200))
18             {
19                 Console.WriteLine("Main thead do work!");
20             }
21             string data=myDelegate.EndInvoke(result);
22             Console.WriteLine(data);
23             
24             Console.ReadKey();
25         }
26 
27         static string Hello(string name)
28         {
29             ThreadMessage("Async Thread");
30             Thread.Sleep(2000);
31             return "Hello " + name;
32         }
33 
34         static void ThreadMessage(string data)
35         {
36             string message = string.Format("{0}\n  ThreadId is:{1}",
37                    data,Thread.CurrentThread.ManagedThreadId);
38             Console.WriteLine(message);
39         }
40     }

图片 66

图片 67

 

当要监视多个运营指标的时候,使用IAsyncResult.WaitHandle.WaitOne可就派不上用场了。
幸而.NET为WaitHandle计划了别的五个静态方法:WaitAny(waitHandle[],
int)与WaitAll (waitHandle[] , int)。
内部WaitAll在等待全部waitHandle完结后再回去七个bool值。
而WaitAny是等待之中五个waitHandle实现后就回到三个int,这几个int是意味着已产生waitHandle在waitHandle[]中的数组索引。
下边就是采纳WaitAll的例子,运维结果与使用 IAsyncResult.IsCompleted
同样。

4.6  善用IAsyncResult

图片 68

在上述例子中得以望见,假使在利用myDelegate.BeginInvoke后旋即调用myDelegate.EndInvoke,那在异步线程未产生专业在此从前主线程将处于阻塞状态,等到异步线程甘休获取计算结果后,主线程技艺持续做事,这鲜明敬谢不敏体现出三三十二线程的优势。此时能够好好利用IAsyncResult
进步主线程的办事性质,IAsyncResult有以下成员:

 1     class Program
 2     {
 3         delegate string MyDelegate(string name);
 4 
 5         static void Main(string[] args)
 6         {
 7             ThreadMessage("Main Thread");
 8             
 9             //建立委托
10             MyDelegate myDelegate = new MyDelegate(Hello);
11  
12             //异步调用委托,获取计算结果
13             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null);
14 
15             //此处可加入多个检测对象
16             WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle,........ };
17             while (!WaitHandle.WaitAll(waitHandleList,200))
18             {
19                 Console.WriteLine("Main thead do work!");
20             }
21             string data=myDelegate.EndInvoke(result);
22             Console.WriteLine(data);
23             
24             Console.ReadKey();
25         }
26 
27         static string Hello(string name)
28         {
29             ThreadMessage("Async Thread");
30             Thread.Sleep(2000);
31             return "Hello " + name;
32         }
33 
34         static void ThreadMessage(string data)
35         {
36             string message = string.Format("{0}\n  ThreadId is:{1}",
37                    data,Thread.CurrentThread.ManagedThreadId);
38             Console.WriteLine(message);
39         }
40     }

图片 69😉

图片 70

1 public interface IAsyncResult
2 {
3     object AsyncState {get;}            //获取用户定义的对象,它限定或包含关于异步操作的信息。
4     WailHandle AsyncWaitHandle {get;}   //获取用于等待异步操作完成的 WaitHandle。
5     bool CompletedSynchronously {get;}  //获取异步操作是否同步完成的指示。
6     bool IsCompleted {get;}             //获取异步操作是否已完成的指示。
7 }

 

图片 71😉

4.7 回调函数

透过轮询情势,使用IsCompleted属性判定异步操作是还是不是做到,那样在异步操作未成功前就能够让主线程实行其余的做事。

采用轮询格局来检验异步方法的情状拾叁分麻烦,并且效用不高,有见及此,.NET为
IAsyncResult BeginInvoke(AsyncCallback ,
object)筹算了二个回调函数。使用 AsyncCallback
就能够绑定多个格局作为回调函数,回调函数必得是带参数 IAsyncResult
且无再次来到值的办法: void AsycnCallbackMethod(IAsyncResult result)
。在BeginInvoke方法成功后,系统就能够调用AsyncCallback所绑定的回调函数,最终回调函数中调用
XXX EndInvoke(IAsyncResult result)
就足以为止异步方法,它的归来值类型与信托的重临值一致。

图片 72😉

图片 73

 1     class Program  2     {  3         delegate string MyDelegate(string name);  4   5         static void Main(string[] args)  6         {  7             ThreadMessage("Main Thread");  8               9             //建立委托 10             MyDelegate myDelegate = new MyDelegate(Hello); 11             //异步调用委托,获取计算结果 12             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null); 13             //在异步线程未完成前执行其他工作 14             while (!result.IsCompleted) 15             { 16                 Thread.Sleep(200);      //虚拟操作 17                 Console.WriteLine("Main thead do work!"); 18             } 19             string data=myDelegate.EndInvoke(result); 20             Console.WriteLine(data); 21              22             Console.ReadKey(); 23         } 24  25         static string Hello(string name) 26         { 27             ThreadMessage("Async Thread"); 28             Thread.Sleep(2000); 29             return "Hello " + name; 30         } 31  32         static void ThreadMessage(string data) 33         { 34             string message = string.Format("{0}\n  ThreadId is:{1}", 35                    data,Thread.CurrentThread.ManagedThreadId); 36             Console.WriteLine(message); 37         } 38     }
 1     class Program
 2     {
 3         delegate string MyDelegate(string name);
 4 
 5         static void Main(string[] args)
 6         {
 7             ThreadMessage("Main Thread");
 8 
 9             //建立委托
10             MyDelegate myDelegate = new MyDelegate(Hello);
11             //异步调用委托,获取计算结果
12             myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), null);
13             //在启动异步线程后,主线程可以继续工作而不需要等待
14             for (int n = 0; n < 6; n++)
15                 Console.WriteLine("  Main thread do work!");
16             Console.WriteLine("");
17 
18             Console.ReadKey();
19         }
20 
21         static string Hello(string name)
22         {
23             ThreadMessage("Async Thread");
24             Thread.Sleep(2000);             \\模拟异步操作
25             return "\nHello " + name;
26         }
27 
28         static void Completed(IAsyncResult result)
29         {
30             ThreadMessage("Async Completed");
31 
32             //获取委托对象,调用EndInvoke方法获取运行结果
33             AsyncResult _result = (AsyncResult)result;
34             MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
35             string data = myDelegate.EndInvoke(_result);
36             Console.WriteLine(data);
37         }
38 
39         static void ThreadMessage(string data)
40         {
41             string message = string.Format("{0}\n  ThreadId is:{1}",
42                    data, Thread.CurrentThread.ManagedThreadId);
43             Console.WriteLine(message);
44         }
45     }

图片 74😉

图片 75

运作结果:

能够看来,主线在调用BeginInvoke方法能够继续实践其余命令,而无需再等待了,那无疑比使用轮询情势推断异步方法是不是成功更有优势。
在异步方法执行到位后将会调用AsyncCallback所绑定的回调函数,注意一点,回调函数依旧是在异步线程中推行,那样就不会影响主线程的运作,那也运用回调函数最值得青昧的地点。
在回调函数中有二个既定的参数IAsyncResult,把IAsyncResult强制调换为AsyncResult后,就可以经过
AsyncResult.AsyncDelegate
获取开始和结果托,再选用EndInvoke方法获得计算结果。
运作结果如下:

图片 76

图片 77

 

假定想为回调函数传送一些外表新闻,就足以应用BeginInvoke(AsyncCallback,object)的结尾叁个参数object,它同意外部向回调函数输入任何项指标参数。只供给在回调函数中运用
AsyncResult.AsyncState 就可以赢得object对象。

除此以外,也得以利用WailHandle完结同样的劳作,WaitHandle里面包括有三个格局WaitOne(int
timeout),它能够推断委托是不是完结职业,在做事未到位前主线程能够一连别的干活。运转上边代码可获得与利用
IAsyncResult.IsCompleted 同样的结果,况兼更简便方便 。

图片 78

图片 79😉

 1     class Program
 2     {
 3         public class Person
 4         {
 5             public string Name;
 6             public int Age;
 7         }
 8 
 9         delegate string MyDelegate(string name);
10 
11         static void Main(string[] args)
12         {
13             ThreadMessage("Main Thread");
14 
15             //建立委托
16             MyDelegate myDelegate = new MyDelegate(Hello);
17             
18             //建立Person对象
19             Person person = new Person();
20             person.Name = "Elva";
21             person.Age = 27;
22             
23             //异步调用委托,输入参数对象person, 获取计算结果
24             myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), person);            
25           
26             //在启动异步线程后,主线程可以继续工作而不需要等待
27             for (int n = 0; n < 6; n++)
28                 Console.WriteLine("  Main thread do work!");
29             Console.WriteLine("");
30 
31             Console.ReadKey();
32         }
33 
34         static string Hello(string name)
35         {
36             ThreadMessage("Async Thread");
37             Thread.Sleep(2000);
38             return "\nHello " + name;
39         }
40 
41         static void Completed(IAsyncResult result)
42         {
43             ThreadMessage("Async Completed");
44 
45             //获取委托对象,调用EndInvoke方法获取运行结果
46             AsyncResult _result = (AsyncResult)result;
47             MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
48             string data = myDelegate.EndInvoke(_result);
49             //获取Person对象
50             Person person = (Person)result.AsyncState;
51             string message = person.Name + "'s age is " + person.Age.ToString();
52 
53             Console.WriteLine(data+"\n"+message);
54         }
55 
56         static void ThreadMessage(string data)
57         {
58             string message = string.Format("{0}\n  ThreadId is:{1}",
59                    data, Thread.CurrentThread.ManagedThreadId);
60             Console.WriteLine(message);
61         }
62     }
 1 namespace Test
 2 {
 3     class Program
 4     {
 5         delegate string MyDelegate(string name);
 6 
 7         static void Main(string[] args)
 8         {
 9             ThreadMessage("Main Thread");
10             
11             //建立委托
12             MyDelegate myDelegate = new MyDelegate(Hello);
13  
14             //异步调用委托,获取计算结果
15             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null);
16             
17             while (!result.AsyncWaitHandle.WaitOne(200))
18             {
19                 Console.WriteLine("Main thead do work!");
20             }
21             string data=myDelegate.EndInvoke(result);
22             Console.WriteLine(data);
23             
24             Console.ReadKey();
25         }
26 
27         static string Hello(string name)
28         {
29             ThreadMessage("Async Thread");
30             Thread.Sleep(2000);
31             return "Hello " + name;
32         }
33 
34         static void ThreadMessage(string data)
35         {
36             string message = string.Format("{0}\n  ThreadId is:{1}",
37                    data,Thread.CurrentThread.ManagedThreadId);
38             Console.WriteLine(message);
39         }
40     }

图片 80

图片 81😉

运行结果:

当要监视多个运营目标的时候,使用IAsyncResult.WaitHandle.WaitOne可就派不上用场了。
幸好.NET为WaitHandle筹划了另外多少个静态方法:WaitAny(waitHandle[],
int)与WaitAll (waitHandle[] , int)。
在那之中WaitAll在守候全部waitHandle完结后再回来一个bool值。
而WaitAny是等待之中一个waitHandle达成后就赶回一个int,这些int是代表已做到waitHandle在waitHandle[]中的数组索引。
上面正是选择WaitAll的例证,运营结果与运用 IAsyncResult.IsCompleted
同样。

图片 82

图片 83😉

 

 1     class Program  2     {  3         delegate string MyDelegate(string name);  4   5         static void Main(string[] args)  6         {  7             ThreadMessage("Main Thread");  8               9             //建立委托 10             MyDelegate myDelegate = new MyDelegate(Hello); 11   12             //异步调用委托,获取计算结果 13             IAsyncResult result=myDelegate.BeginInvoke("Leslie", null, null); 14  15             //此处可加入多个检测对象 16             WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle,........ }; 17             while (!WaitHandle.WaitAll(waitHandleList,200)) 18             { 19                 Console.WriteLine("Main thead do work!"); 20             } 21             string data=myDelegate.EndInvoke(result); 22             Console.WriteLine(data); 23              24             Console.ReadKey(); 25         } 26  27         static string Hello(string name) 28         { 29             ThreadMessage("Async Thread"); 30             Thread.Sleep(2000); 31             return "Hello " + name; 32         } 33  34         static void ThreadMessage(string data) 35         { 36             string message = string.Format("{0}\n  ThreadId is:{1}", 37                    data,Thread.CurrentThread.ManagedThreadId); 38             Console.WriteLine(message); 39         } 40     }

转载于:http://www.cnblogs.com/leslies2/archive/2012/02/07/2310495.html
 

图片 84😉

 

4.7 回调函数

选择轮询情势来检查测试异步方法的意况特别麻烦,并且成效不高,有见及此,.NET为
IAsyncResult BeginInvoke(AsyncCallback ,
object)筹划了四个回调函数。使用 AsyncCallback
就能够绑定八个格局作为回调函数,回调函数必需是带参数 IAsyncResult
且无再次回到值的不二秘籍: void AsycnCallbackMethod(IAsyncResult result)
。在BeginInvoke方法成功后,系统就会调用AsyncCallback所绑定的回调函数,最终回调函数中调用
XXX EndInvoke(IAsyncResult result)
就足以截至异步方法,它的归来值类型与信托的重回值一致。

图片 85😉

 1     class Program
 2     {
 3         delegate string MyDelegate(string name);
 4 
 5         static void Main(string[] args)
 6         {
 7             ThreadMessage("Main Thread");
 8 
 9             //建立委托
10             MyDelegate myDelegate = new MyDelegate(Hello);
11             //异步调用委托,获取计算结果
12             myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), null);
13             //在启动异步线程后,主线程可以继续工作而不需要等待
14             for (int n = 0; n < 6; n++)
15                 Console.WriteLine("  Main thread do work!");
16             Console.WriteLine("");
17 
18             Console.ReadKey();
19         }
20 
21         static string Hello(string name)
22         {
23             ThreadMessage("Async Thread");
24             Thread.Sleep(2000);             \\模拟异步操作
25             return "\nHello " + name;
26         }
27 
28         static void Completed(IAsyncResult result)
29         {
30             ThreadMessage("Async Completed");
31 
32             //获取委托对象,调用EndInvoke方法获取运行结果
33             AsyncResult _result = (AsyncResult)result;
34             MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate;
35             string data = myDelegate.EndInvoke(_result);
36             Console.WriteLine(data);
37         }
38 
39         static void ThreadMessage(string data)
40         {
41             string message = string.Format("{0}\n  ThreadId is:{1}",
42                    data, Thread.CurrentThread.ManagedThreadId);
43             Console.WriteLine(message);
44         }
45     }

图片 86😉

能够看看,主线在调用BeginInvoke方法能够继续施行别的命令,而没有要求再等待了,这无可争辩比选拔轮询方式决断异步方法是不是到位更有优势。
在异步方法施行到位后将会调用AsyncCallback所绑定的回调函数,注意一点,回调函数照旧是在异步线程中进行,那样就不会耳濡目染主线程的运转,那也利用回调函数最值得青昧的地点。
在回调函数中有二个既定的参数IAsyncResult,把IAsyncResult强制转变为AsyncResult后,就能够透过
AsyncResult.AsyncDelegate 获取始末托,再选取EndInvoke方法赢得总括结果。
运转结果如下:

图片 87

如果想为回调函数字传送送一些外表音信,就能够使用BeginInvoke(AsyncCallback,object)的末尾二个参数object,它同意外界向回调函数输入任何类型的参数。只须要在回调函数中利用
AsyncResult.AsyncState 就足以博得object对象。

图片 88😉

 1     class Program  2     {  3         public class Person  4         {  5             public string Name;  6             public int Age;  7         }  8   9         delegate string MyDelegate(string name); 10  11         static void Main(string[] args) 12         { 13             ThreadMessage("Main Thread"); 14  15             //建立委托 16             MyDelegate myDelegate = new MyDelegate(Hello); 17              18             //建立Person对象 19             Person person = new Person(); 20             person.Name = "Elva"; 21             person.Age = 27; 22              23             //异步调用委托,输入参数对象person, 获取计算结果 24             myDelegate.BeginInvoke("Leslie", new AsyncCallback(Completed), person);             25            26             //在启动异步线程后,主线程可以继续工作而不需要等待 27             for (int n = 0; n < 6; n++) 28                 Console.WriteLine("  Main thread do work!"); 29             Console.WriteLine(""); 30  31             Console.ReadKey(); 32         } 33  34         static string Hello(string name) 35         { 36             ThreadMessage("Async Thread"); 37             Thread.Sleep(2000); 38             return "\nHello " + name; 39         } 40  41         static void Completed(IAsyncResult result) 42         { 43             ThreadMessage("Async Completed"); 44  45             //获取委托对象,调用EndInvoke方法获取运行结果 46             AsyncResult _result = (AsyncResult)result; 47             MyDelegate myDelegate = (MyDelegate)_result.AsyncDelegate; 48             string data = myDelegate.EndInvoke(_result); 49             //获取Person对象 50             Person person = (Person)result.AsyncState; 51             string message = person.Name + "'s age is " + person.Age.ToString(); 52  53             Console.WriteLine(data+"\n"+message); 54         } 55  56         static void ThreadMessage(string data) 57         { 58             string message = string.Format("{0}\n  ThreadId is:{1}", 59                    data, Thread.CurrentThread.ManagedThreadId); 60             Console.WriteLine(message); 61         } 62     }

图片 89😉

运作结果:

图片 90

 

有关I/O线程、SqlCommand三十二线程查询、PLINQ、放大计时器与锁的源委将在C#归结揭秘——细说二十四线程(下)中详细介绍。
对 .NET 开拓风野趣的对象招待参加QQ群:230564952
共同研讨 !

回来目录

C#归纳揭秘

透过修改注册表创立Windows自定义合同
Entity Framework
并发管理详解
前述进度、应用程序域与上下文

细说二十四线程(上)

前述二十八线程(下) 前述事务浓厚分析委托与事件

 

笔者:风尘浪子 http://www.cnblogs.com/leslies2/archive/2012/02/07/2310495.html

原创小说,转发时请表明作者及出处

 

 

 

分类:
C#总结揭秘