更应该多留意I/O线程的操作,更应当多留意I/O线程的操作

引言

引言

正文主要从线程的底蕴用法,CLR线程池当中工小编线程与I/O线程的花费,并行操作PLINQ等八个方面介绍多线程的支付。
其中委托的BeginInvoke方法以及回调函数最为常用。 而
I/O线程可能不难蒙受我们的疏忽,其实在支付多线程系统,更应当多留意I/O线程的操作。尤其是在ASP.NET开发当中,可能更几人只会小心在客户端接纳Ajax或者在劳务器端使用UpdatePanel。其实入情入理施用I/O线程在通讯项目或文件下载时,能尽可能地减弱IIS的下压力。
并行编程是Framework4.0中大力推广的异步操作方式,更值得更尖锐地读书。
希望本篇文章能对各位的学习研商有着协理,当中有所错漏的地点敬请点评。

本文主要从线程的功底用法,CLR线程池当中工小编线程与I/O线程的支付,并行操作PLINQ等两个地点介绍多线程的花费。
中间委托的BeginInvoke方法以及回调函数最为常用。

I/O线程可能不难遇到我们的不经意,其实在付出多线程系统,更应该多留意I/O线程的操作。越发是在ASP.NET开发当中,可能更五个人只会注目的在于客户端应用Ajax或者在服务器端使用UpdatePanel。其实合情合理利用I/O线程在通讯项目或文件下载时,能尽量地回落IIS的压力。
互相编程是Framework4.0中努力推广的异步操作办法,更值得更透彻地上学。
指望本篇文章能对各位的就学探究有着协理,当中有所错漏的地方敬请点评。

 

 

 

 

目录

目录

一、线程的定义

一、线程的定义

二、线程的基础知识

二、线程的基础知识

三、以ThreadStart形式完结多线程

三、以ThreadStart方式已毕多线程

四、CLR线程池的劳力线程

四、CLR线程池的工小编线程

五、CLR线程池的I/O线程

五、CLR线程池的I/O线程

六、异步
SqlCommand

六、异步
SqlCommand

七、并行编程与PLINQ

七、并行编程与PLINQ

八、计时器与锁

八、计时器与锁

 

 

 

 

 

 

 

 

一、线程的概念

一、线程的定义

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

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

经过(Process)是Windows系统中的一个基本概念,它包括着一个周转程序所急需的资源。进度之间是相对独立的,一个进度不可以访问另一个经过的多少(除非选拔分布式统计方式),一个历程运行的失利也不会影响其他进度的运行,Windows系统就是选择进程把工作划分为五个独立的区域的。进程可以知道为一个程序的中坚边界。

经过(Process)是Windows系统中的一个基本概念,它涵盖着一个运行程序所须求的资源。进程之间是相持独立的,一个历程无法访问另一个进程的数目(除非选用分布式计算方式),一个进程运行的挫折也不会影响其他进度的运作,Windows系统就是使用进度把工作划分为三个独立的区域的。进度可以知晓为一个顺序的中坚边界。

动用程序域(AppDomain)是一个程序运行的逻辑区域,它可以算得一个轻量级的历程,.NET的顺序集正是在应用程序域中运行的,一个经过能够分包有八个利用程序域,一个用到程序域也足以涵盖四个程序集。在一个使用程序域中隐含了一个或几个左右文context,使用前后文CLR就可知把一些特殊目的的气象放置在不相同容器当中。

选择程序域(AppDomain)是一个程序运行的逻辑区域,它可以视为一个轻量级的经过,.NET的先后集正是在接纳程序域中运行的,一个进程可以分包有四个利用程序域,一个使用程序域也得以分包六个程序集。在一个利用程序域中富含了一个或两个左右文context,使用前后文CLR就可以把某些特殊目标的情景放置在不一样容器当中。

线程(Thread)是进度中的基本进行单元,在经过入口实施的首先个线程被视为这一个进度的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此办法时系统就会自动创制一个主线程。线程重如果由CPU寄存器、调用栈和线程本地存储器(Thread
Local
Storage,TLS)组成的。CPU寄存爱戴要记录当前所执行线程的境况,调用栈主要用于尊崇线程所调用到的内存与数码,TLS主要用以存放线程的场合音讯。

线程(Thread)是进度中的基本举行单元,在经过入口实施的首先个线程被视为这些进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此措施时系统就会自行创造一个主线程。线程首如若由CPU寄存器、调用栈和线程本地存储器(Thread
Local
Storage,TLS)组成的。CPU寄存器主要记录当前所实施线程的状态,调用栈首要用以掩护线程所调用到的内存与数量,TLS主要用来存放线程的动静新闻。

经过、应用程序域、线程的关系如下图,一个历程内足以包罗八个利用程序域,也有囊括三个线程,线程也得以穿梭于六个利用程序域当中。但在同一个每日,线程只会处在一个应用程序域内。

进度、应用程序域、线程的关系如下图,一个历程内足以概括五个使用程序域,也有囊括几个线程,线程也得以穿梭于两个利用程序域当中。但在同一个整日,线程只会处于一个用到程序域内。

 

 

图片 1

图片 2

 
由于本文是以介绍多线程技术为主旨,对进程、应用程序域的牵线就到此甘休。关于进度、线程、应用程序域的技能,在“C#概括揭秘——细说进程、应用程序域与上下文”会有详实介绍。

 
由于本文是以介绍多线程技术为焦点,对进度、应用程序域的牵线就到此甘休。关于进度、线程、应用程序域的技巧,在“C#综合揭秘——细说进度、应用程序域与上下文”会有详尽介绍。

 

 

1.2 多线程

1.2 多线程

在单CPU系统的一个单位时间(time
slice)内,CPU只能运行单个线程,运行顺序取决于线程的预先级别。如若在单位时间内线程未能形成实施,系统就会把线程的情事新闻保存到线程的地方存储器(TLS)
中,以便下次执行时上升执行。而多线程只是系统带来的一个假像,它在几个单位时间内开展五个线程的切换。因为切换频密而且单位时间卓殊短暂,所以多线程可被看做同时运转。

在单CPU系统的一个单位时间(time
slice)内,CPU只好运行单个线程,运行顺序取决于线程的预先级别。假若在单位时间内线程未能形成实施,系统就会把线程的图景信息保存到线程的地面存储器(TLS)
中,以便下次执行时上涨执行。而多线程只是系统带来的一个假像,它在几个单位时间内开展五个线程的切换。因为切换频密而且单位时间格外短暂,所以多线程可被用作同时运转。

适中拔取多线程能增进系统的特性,比如:在系统请求大容量的数码时拔取多线程,把数量输出工作交给异步线程,使主线程保持其安居去处理任何问题。但需求注意一点,因为CPU要求开支不少的光阴在线程的切换上,所以重重地动用多线程反而会促成性能的下滑。

适中使用多线程能增高系统的特性,比如:在系统请求大容量的数码时行使多线程,把多少输出工作付出异步线程,使主线程保持其稳定去处理其余题材。但要求留意一点,因为CPU需求费用不少的年华在线程的切换上,所以广大地运用多线程反而会导致性能的下滑。

 

 

回来目录

回到目录

二、线程的基础知识

二、线程的基础知识

2.1 System.Threading.Thread类

2.1 System.Threading.Thread类

System.Threading.Thread是用以控制线程的基本功类,通过Thread可以决定当前应用程序域中线程的始建、挂起、甘休、销毁。

System.Threading.Thread是用以控制线程的底子类,通过Thread可以决定当前利用程序域中线程的创办、挂起、甘休、销毁。

它概括以下常用公共属性:

它概括以下常用公共性质:

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

 

 

2.1.1 线程的标识符

2.1.1 线程的标识符

ManagedThreadId是认可线程的唯一标识符,程序在多数景况下都是经过Thread.ManagedThreadId来识别线程的。而Name是一个可变值,在默许时候,Name为一个空值
Null,开发人员可以由此程序设置线程的称号,但那只是一个援救功用。

ManagedThreadId是认同线程的绝无仅有标识符,程序在半数以上景况下都是透过Thread.ManagedThreadId来识别线程的。而Name是一个可变值,在默许时候,Name为一个空值
Null,开发人士可以经进程序设置线程的名目,但那只是一个拉扯效能。

 

 

2.1.2 线程的事先级别

2.1.2 线程的预先级别

.NET为线程设置了Priority属性来定义线程执行的优先级别,里面富含5个挑选,其中诺玛(Norma)l是默许值。除非系统有特殊须要,否则不应该随便设置线程的先期级别。

.NET为线程设置了Priority属性来定义线程执行的先行级别,里面富含5个选项,其中Normal是默许值。除非系统有特殊要求,否则不该随便设置线程的预先级别。

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

 

 

2.1.3 线程的境况

2.1.3 线程的情景

经过ThreadState可以检测线程是地处Unstarted、Sleeping、Running
等等状态,它比 IsAlive 属性能提供越来越多的特定音讯。

因而ThreadState可以检测线程是高居Unstarted、Sleeping、Running
等等状态,它比 IsAlive 属性能提供更加多的一定信息。

前边说过,一个利用程序域中或者包涵三个上下文,而透过CurrentContext可以得到线程当前的上下文。

前方说过,一个用到程序域中可能包含七个上下文,而因而CurrentContext可以拿走线程当前的上下文。

CurrentThread是最常用的一个性质,它是用以获取当前运行的线程。

CurrentThread是最常用的一个性质,它是用来获取当前运行的线程。

 

 

2.1.4 System.Threading.Thread的方法

2.1.4 System.Threading.Thread的方法

Thread
中蕴涵了六个情势来控制线程的创建、挂起、为止、销毁,以后来的例子中会平时利用。

Thread
中包罗了三个措施来支配线程的始建、挂起、为止、销毁,以后来的例证中会日常应用。

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

 

 

2.1.5 开发实例

2.1.5 开发实例

以下那些事例,就是经过Thread突显当前线程消息

以下这一个例子,就是通过Thread展现当前线程新闻

图片 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         }
 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         }

 

图片 4😉

运转结果

 

图片 5

运作结果

 

图片 6

2.2  System.Threading 命名空间

 

在System.Threading命名空间内提供三个方法来构建多线程应用程序,其中ThreadPool与Thread是多线程开发中最常用到的,在.NET中越发设定了一个CLR线程池专门用于管理线程的周转,这几个CLR线程池正是经过ThreadPool类来管理。而Thread是管制线程的最直白格局,上边几节将详细介绍有关内容。

2.2  System.Threading 命名空间

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

在System.Threading命名空间内提供几个主意来构建多线程应用程序,其中ThreadPool与Thread是多线程开发中最常用到的,在.NET中特意设定了一个CLR线程池专门用来管理线程的运行,这几个CLR线程池正是通过ThreadPool类来保管。而Thread是管制线程的最直白格局,下边几节将详细介绍有关内容。

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

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

在System.Threading中的包蕴了下表中的四个常用委托,其中ThreadStart、ParameterizedThreadStart是最常用到的委托。
由ThreadStart生成的线程是最直白的章程,但由ThreadStart所生成并不受线程池管理。
而ParameterizedThreadStart是为异步触发带参数的艺术而设的,在下一节将为我们逐一细说。

 

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

2.3 线程的管制章程

 

经过ThreadStart来创立一个新线程是最直白的章程,但那样创设出来的线程比较难管理,假使创立过多的线程反而会让系统的性质下载。有见及此,.NET为线程管理专门设置了一个CLR线程池,使用CLR线程池系统可以更客观地管理线程的运用。所有请求的服务都能运行于线程池中,当运行为止时线程便会回归到线程池。通过安装,能控制线程池的最大线程数量,在哀告超出线程最大值时,线程池能按照操作的事先级别来施行,让部分操作处于等候状态,待有线程回归时再进行操作。

2.3 线程的管住章程

基础知识就为大家介绍到此地,下边将详细介绍多线程的支付。

由此ThreadStart来创建一个新线程是最直接的办法,但这么创制出来的线程相比难管理,假若创造过多的线程反而会让系统的性能下载。有见及此,.NET为线程管理更加设置了一个CLR线程池,使用CLR线程池系统可以更合理地保管线程的利用。所有请求的劳动都能运作于线程池中,当运行甘休时线程便会回归到线程池。通过设置,能控制线程池的最大线程数量,在哀告超出线程最大值时,线程池能根据操作的先行级别来执行,让部分操作处于等候景况,待有线程回归时再履行操作。

 

基础知识就为大家介绍到此地,下边将详细介绍多线程的开发。

 

 

归来目录

 

三、以ThreadStart格局贯彻多线程

再次回到目录

3.1 使用ThreadStart委托

三、以ThreadStart方式贯彻多线程

那里先以一个例证显示一下多线程带来的裨益,首先在Message类中建立一个方法ShowMessage(),里面呈现了眼前运作线程的Id,并动用Thread.Sleep(int
)
方法模拟部分工作。在main()中经过ThreadStart委托绑定Message对象的ShowMessage()方法,然后通过Thread.Start()执行异步方法。

3.1 使用ThreadStart委托

 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       }

此间先以一个例证体现一下多线程带来的利益,首先在Message类中创建一个办法ShowMessage(),里面突显了当前运行线程的Id,并采取Thread.Sleep(int
)
方法模拟部分工作。在main()中通过ThreadStart委托绑定Message对象的ShowMessage()方法,然后通过Thread.Start()执行异步方法。

请留心运行结果,在调用Thread.Start()方法后,系统以异步格局运行Message.ShowMessage(),而主线程的操作是继续执行的,在Message.ShowMessage()落成前,主线程已做到所有的操作。

图片 7😉

图片 8

 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       }

 

图片 9😉

3.2 使用ParameterizedThreadStart委托

请小心运行结果,在调用Thread.Start()方法后,系统以异步格局运行Message.ShowMessage(),而主线程的操作是继续执行的,在Message.ShowMessage()完结前,主线程已做到有着的操作。

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

图片 10

 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     }

 

运转结果:

3.2 使用ParameterizedThreadStart委托

图片 11

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

 

图片 12😉

3.3 前台线程与后台线程

 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     }

专注上述几个例证都未曾使用Console.ReadKey(),但系统如故会等待异步线程落成后才会完成。那是因为使用Thread.Start()启动的线程默许为前台线程,而系统必须等待所有前台线程运行甘休后,应用程序域才会自行卸载。

图片 13😉

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

运行结果:

 

图片 14

3.4 挂起线程

 

为了等待其他后台线程实现后再截止主线程,就足以行使Thread.Sleep()方法。

3.3 前台线程与后台线程

 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     }

小心上述八个例证都并未运用Console.ReadKey(),但系统依然会等待异步线程完毕后才会甘休。那是因为运用Thread.Start()启动的线程默许为前台线程,而系统必须等待所有前台线程运行截至后,应用程序域才会自动卸载。

运行结果如下,此时应用程序域将在主线程运行5秒后自动终止

在第三节曾经介绍过线程Thread有一个属性IsBackground,通过把此属性设置为true,就足以把线程设置为后台线程!这时应用程序域将在主线程已毕时就被卸载,而不会等待异步线程的运作。

图片 15

 

 

3.4 挂起线程

但系统不能预言异步线程需求周转的日子,所以用经过Thread.Sleep(int)阻塞主线程并不是一个好的化解方法。有见及此,.NET专门为等候异步线程实现支付了另一个艺术thread.Join()。把地方例子中的最终一行Thread.Sleep(5000)修改为
thread.Join() 就能确保主线程在异步线程thread运行停止后才会停下。

为了等待其余后台线程落成后再截止主线程,就足以选择Thread.Sleep()方法。

 

图片 16😉

3.5 Suspend 与 Resume (慎用)

 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     }

Thread.Suspend()与 Thread.Resume()是在Framework1.0
就早已存在的老方法了,它们各自可以挂起、苏醒线程。但在Framework2.0中就曾经显著排斥那七个办法。那是因为若是某个线程占用了已部分资源,再利用Suspend()使线程长时间高居挂起状态,当在其余线程调用那个资源的时候就会滋生死锁!所以在没有须要的情形下应当防止采纳那三个格局。

图片 17😉

 

运行结果如下,此时利用程序域将在主线程运行5秒后活动终止

3.6 终止线程

图片 18

若想终止正在周转的线程,可以使用Abort()方法。在应用Abort()的时候,将掀起一个杰出格外ThreadAbortException 。
若想在线程终止前復苏线程的实践,可以在抓获非常后
,在catch(ThreadAbortException ex){…}
中调用Thread.ResetAbort()撤废终止。
而选用Thread.Join()能够有限支持应用程序域等待异步线程截至后才停下运行。

 

 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          }

但系统不能够预见异步线程必要周转的时光,所以用经过Thread.Sleep(int)阻塞主线程并不是一个好的解决情势。有见及此,.NET专门为等候异步线程完毕支付了另一个主意thread.Join()。把地点例子中的最终一行Thread.Sleep(5000)修改为
thread.Join() 就能确保主线程在异步线程thread运行停止后才会告一段落。

运作结果如下

 

图片 19

3.5 Suspend 与 Resume (慎用)

 

Thread.Suspend()与 Thread.Resume()是在Framework1.0
就早已存在的老方法了,它们各自可以挂起、苏醒线程。但在Framework2.0中就曾经明朗排斥那六个主意。那是因为只要某个线程占用了已部分资源,再使用Suspend()使线程长时间居于挂起状态,当在别的线程调用那一个资源的时候就会滋生死锁!所以在一贯不要求的场所下应该防止使用那三个法子。

 

 

回去目录

3.6 终止线程

四、CLR线程池的劳力线程

若想终止正在运作的线程,可以利用Abort()方法。在采纳Abort()的时候,将吸引一个出奇极度ThreadAbortException 。 若想在线程终止前復苏线程的履行,可以在抓获分外后
,在catch(ThreadAbortException ex){…}
中调用Thread.ResetAbort()裁撤终止。
而使用Thread.Join()可以确保应用程序域等待异步线程停止后才止住运行。

4.1 关于CLR线程池

图片 20😉

行使ThreadStart与ParameterizedThreadStart建立新线程格外简单,但透过此措施创制的线程难于管理,若建立过多的线程反而会影响系统的性质。
有见及此,.NET引入CLR线程池那些概念。CLR线程池并不会在CLR开头化的时候立刻创设线程,而是在应用程序要开创线程来进行职分时,线程池才开头化一个线程。线程的初阶化与其它的线程一样。在成就任务之后,该线程不会活动销毁,而是以挂起的动静再次回到到线程池。直到应用程序再一次向线程池发出请求时,线程池里挂起的线程就会再次激活执行职责。那样既节约了创制线程所导致的特性损耗,也足以让几个义务反复重用同一线程,从而在应用程序生存期内节约大量费用。

 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          }

注意通过CLR线程池所建立的线程总是默许为后台线程,优先级数为ThreadPriority.Normal。

图片 21😉

 

运作结果如下

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

图片 22

CLR线程池分为工作者线程(workerThreads)与I/O线程 (completionPortThreads)
三种,工小编线程是重中之重用作管理CLR内部对象的周转,I/O(Input/Output)
线程顾名思义是用以与外部系统交流信息,IO线程的底细将在下一节详细表达。

 

经过ThreadPool.GetMax(out int workerThreads,out int
completionPortThreads )和 ThreadPool.SetMax(Max)( int workerThreads, int
completionPortThreads)三个形式可以分别读取和安装CLR线程池中工小编线程与I/O线程的最大线程数。在Framework2.0中最大线程默许为25*CPU数,在Framewok3.0、4.0中最大线程数默许为250*CPU数,在近年来I3,I5,I7 CPU出现后,线程池的最大值一般默许为1000、2000。
若想测试线程池中有微微的线程正在投入使用,能够透过ThreadPool.GetAvailableThreads(
out int workerThreads,out int
completionPortThreads ) 方法。

 

利用CLR线程池的劳力线程一般有三种方式,一是一贯通过
ThreadPool.QueueUserWorkItem() 方法,二是通过信托,上边将相继细说。

重返目录

 

四、CLR线程池的劳引力线程

4.3 通过QueueUserWorkItem启动工小编线程

4.1 关于CLR线程池

ThreadPool线程池中涵盖有两个静态方法可以一向开行工小编线程:
一为 ThreadPool.QueueUserWorkItem(WaitCallback)
二为 ThreadPool.QueueUserWorkItem(WaitCallback,Object) 

运用ThreadStart与ParameterizedThreadStart建立新线程格外不难,但通过此办法成立的线程难于管理,若建立过多的线程反而会影响系统的性能。
有见及此,.NET引入CLR线程池那一个定义。CLR线程池并不会在CLR初步化的时候立时创设线程,而是在应用程序要创制线程来执行职务时,线程池才初阶化一个线程。线程的初步化与其余的线程一样。在做到义务之后,该线程不会自行销毁,而是以挂起的情形重返到线程池。直到应用程序再一次向线程池发出请求时,线程池里挂起的线程就会再次激活执行任务。那样既省去了树立线程所导致的性能损耗,也可以让五个职分反复重用同一线程,从而在应用程序生存期内节约大批量开支。

先把WaitCallback委托指向一个涵盖Object参数的无重回值方法,再选拔ThreadPool.QueueUserWorkItem(WaitCallback)
就可以异步启动此措施,此时异步方法的参数被视为null 。

注意透过CLR线程池所确立的线程总是默许为后台线程,优先级数为ThreadPriority.诺玛l。

 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     }

 

运作结果

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

图片 23

CLR线程池分为工作者线程(workerThreads)与I/O线程 (completionPortThreads)
三种,工小编线程是主要用作管理CLR内部对象的运行,I/O(Input/Output)
线程顾名思义是用来与外表系统交流音讯,IO线程的底细将在下一节详细表达。

 

因而ThreadPool.GetMax(Max)(out int workerThreads,out int
completionPortThreads )和 ThreadPool.SetMax( int workerThreads, int
completionPortThreads)八个格局可以分别读取和安装CLR线程池中工小编线程与I/O线程的最大线程数。在Framework2.0中最大线程默许为25*CPU数,在Framewok3.0、4.0中最大线程数默许为250*CPU数,在近年
I3,I5,I7 CPU现身后,线程池的最大值一般默许为1000、2000。
若想测试线程池中有稍许的线程正在投入使用,可以透过ThreadPool.GetAvailableThreads(
out int workerThreads,out int
completionPortThreads ) 方法。

运用 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
方法可以把object对象作为参数传送到回调函数中。
上边例子中就是把一个string对象作为参数发送到回调函数当中。

利用CLR线程池的工小编线程一般有二种方法,一是一贯通过
ThreadPool.QueueUserWorkItem() 方法,二是透过信托,上边将各类细说。

 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.3 通过QueueUserWorkItem启动工小编线程

图片 24

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

 

先把WaitCallback委托指向一个包含Object参数的无再次来到值方法,再利用
ThreadPool.QueueUserWorkItem(WaitCallback)
就足以异步启动此措施,此时异步方法的参数被视为null 。

因而ThreadPool.QueueUserWorkItem启动工小编线程固然是有利于,但WaitCallback委托指向的总得是一个暗含Object参数的无重回值方法,那毋庸置疑是一种范围。若方法需求有再次来到值,或者隐含两个参数,那将多费周折。有见及此,.NET提供了另一种方法去建立工小编线程,那就是信托。

图片 25😉

 

 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     }

4.4  委托类       

图片 26😉

使用CLR线程池中的工小编线程,最灵敏最常用的法门就是选择委托的异步方法,在此先简单介绍一下委托类。

运行结果

当定义委托后,.NET就会自行成立一个表示该信托的类,上面能够用反射情势体现委托类的法子成员(对反射有趣味的爱侣可以先参考一下“.NET基础篇——反射的微妙”)

图片 27

 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      }

 

委托类包含以下几个至关紧要措施

动用 ThreadPool.QueueUserWorkItem(WaitCallback,Object)
方法可以把object对象作为参数传送到回调函数中。
上边例子中就是把一个string对象作为参数发送到回调函数当中。

图片 28

图片 29😉

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     }

当调用Invoke()方法时,对应此委托的有所办法都会被执行。而BeginInvoke与EndInvoke则帮衬委托方法的异步调用,由BeginInvoke启动的线程都属于CLR线程池中的工小编线程,在底下将详细表明。

图片 30😉

 

运作结果

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

图片 31

第一建立一个信托对象,通过IAsyncResult BeginInvoke(string
name,AsyncCallback callback,object state) 异步调用委托方法,BeginInvoke
方法除最后的八个参数外,别的参数都是与方法参数相呼应的。通过 BeginInvoke
方法将回来一个贯彻了 System.IAsyncResult
接口的对象,之后就足以运用EndInvoke(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             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     }

通过ThreadPool.QueueUserWorkItem启动工小编线程纵然是福利,但WaitCallback委托指向的必须是一个饱含Object参数的无重返值方法,那的确是一种范围。若方法需求有再次来到值,或者隐含八个参数,那将多费周折。有见及此,.NET提供了另一种办法去建立工小编线程,那就是委托。

运行结果

 

图片 32

4.4  委托类       

 

选取CLR线程池中的工小编线程,最灵敏最常用的艺术就是运用委托的异步方法,在此先简单介绍一下委托类。

4.6  善用IAsyncResult

当定义委托后,.NET就会自行创立一个意味着该信托的类,上面可以用反射形式体现委托类的格局成员(对反射有趣味的恋人可以先参考一下“.NET基础篇——反射的微妙”)

在以上例子中得以望见,若是在选取myDelegate.BeginInvoke后登时调用myDelegate.EndInvoke,那在异步线程未成功工作从前主线程将处于阻塞状态,等到异步线程截止获取总结结果后,主线程才能持续做事,那明显不可以显示出多线程的优势。此时得以可以利用IAsyncResult
提升主线程的干活性质,IAsyncResult有以下成员:

图片 33😉

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

经过轮询形式,使用IsCompleted属性判断异步操作是否形成,那样在异步操作未到位前就足以让主线程执行其余的工作。

图片 34😉

 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     }

委托类包涵以下几个紧要形式

运行结果:

图片 35

图片 36

图片 37😉

 

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     }

除此以外,也足以动用WailHandle完结同样的办事,WaitHandle里面含有有一个艺术WaitOne(int
timeout),它可以断定委托是否成功工作,在办事未成功前主线程可以继承其余干活。运行下边代码可收获与行使
IAsyncResult.IsCompleted 同样的结果,而且更简便方便 。

图片 38😉

 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     }

当调用Invoke()方法时,对应此委托的具有办法都会被执行。而BeginInvoke与EndInvoke则援救委托方法的异步调用,由BeginInvoke启动的线程都属于CLR线程池中的工小编线程,在底下将详细表达。

当要监视八个运行目的的时候,使用IAsyncResult.WaitHandle.WaitOne可就派不上用场了。
幸好.NET为WaitHandle准备了其它五个静态方法:WaitAny(waitHandle[],
int)与WaitAll (waitHandle[] , int)。
中间WaitAll在等待所有waitHandle已毕后再回到一个bool值。
而WaitAny是伺机之中一个waitHandle完成后就回来一个int,这一个int是象征已做到waitHandle在waitHandle[]中的数组索引。
上面就是使用WaitAll的例子,运行结果与利用 IAsyncResult.IsCompleted
相同。

 

 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     }

4.5  利用BeginInvoke与EndInvoke落成异步委托方法

 

率先创制一个信托对象,通过IAsyncResult BeginInvoke(string
name,AsyncCallback callback,object state) 异步调用委托方法,BeginInvoke
方法除最终的三个参数外,其他参数都是与办法参数相对应的。通过 BeginInvoke
方法将再次回到一个兑现了 System.IAsyncResult
接口的靶子,之后就可以利用EndInvoke(IAsyncResult )
方法就足以终结异步操作,获取委托的运行结果。

4.7 回调函数

图片 39😉

选择轮询格局来检测异步方法的情状尤其劳碌,而且功能不高,有见及此,.NET为
IAsyncResult BeginInvoke(AsyncCallback ,
object)准备了一个回调函数。使用 AsyncCallback
就足以绑定一个艺术作为回调函数,回调函数必须是带参数 IAsyncResult
且无重临值的方法: void AsycnCallbackMethod(IAsyncResult result)
。在BeginInvoke方法成功后,系统就会调用AsyncCallback所绑定的回调函数,最终回调函数中调用
XXX EndInvoke(IAsyncResult result)
就足以终结异步方法,它的归来值类型与信托的再次回到值一致。

 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     }
 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     }

图片 40😉

可以见到,主线在调用BeginInvoke方法可以继续执行其余命令,而无需再伺机了,那如实比使用轮询格局判断异步方法是否成功更有优势。
在异步方法执行到位后将会调用AsyncCallback所绑定的回调函数,注意一点,回调函数如故是在异步线程中施行,那样就不会影响主线程的运行,那也应用回调函数最值得青昧的地点。
在回调函数中有一个既定的参数IAsyncResult,把IAsyncResult强制转换为AsyncResult后,就足以由此AsyncResult.AsyncDelegate
获取原委托,再接纳EndInvoke方法取得统计结果。
运作结果如下:

运转结果

图片 41

图片 42

假诺想为回调函数传送一些外表音讯,就足以应用BeginInvoke(AsyncCallback,object)的末梢一个参数object,它同意外部向回调函数输入任何项目的参数。只须求在回调函数中选择AsyncResult.AsyncState 就可以赢得object对象。

 

 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     }

4.6  善用IAsyncResult

运行结果:

在上述例子中得以看见,如果在选择myDelegate.BeginInvoke后立时调用myDelegate.EndInvoke,那在异步线程未到位工作从前主线程将处于阻塞状态,等到异步线程为止获取总括结果后,主线程才能继承做事,那明摆着力不从心浮现出多线程的优势。此时可以好好利用IAsyncResult
升高主线程的办事性质,IAsyncResult有以下成员:

图片 43

图片 44😉

 

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

有关I/O线程、SqlCommand多线程查询、PLINQ、定时器与锁的情节将在C#归咎揭秘——细说多线程(下)中详尽介绍。
对 .NET 开发有趣味的爱侣欢迎参与QQ群:230564952
共同切磋 !

图片 45😉

归来目录

经过轮询格局,使用IsCompleted属性判断异步操作是否完结,那样在异步操作未到位前就足以让主线程执行其余的行事。

C#归结揭秘

图片 46😉

因此改动注册表建立Windows自定义协议
Entity Framework
并发处理详解

前述进度、应用程序域与上下文

前述多线程(上)

 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     }

前述多线程(下)
细说事务 长远解析委托与事件

图片 47😉

 

运行结果:

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

图片 48

原创小说,转发时请申明小编及出处

 

 

除此以外,也可以利用WailHandle落成同样的做事,WaitHandle里面含有有一个办法WaitOne(int
timeout),它可以断定委托是否成功工作,在办事未成功前主线程可以一连其余工作。运行上面代码可获取与行使
IAsyncResult.IsCompleted 同样的结果,而且更简便易行方便 。

图片 49😉

 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     }

图片 50😉

当要监视七个运行目的的时候,使用IAsyncResult.WaitHandle.WaitOne可就派不上用场了。
幸好.NET为WaitHandle准备了此外八个静态方法:WaitAny(waitHandle[],
int)与WaitAll (waitHandle[] , int)。
其中WaitAll在等候所有waitHandle落成后再回去一个bool值。
而WaitAny是等待之中一个waitHandle完成后就回来一个int,那些int是象征已成功waitHandle在waitHandle[]中的数组索引。
上边就是利用WaitAll的例子,运行结果与利用 IAsyncResult.IsCompleted
相同。

图片 51😉

 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     }

图片 52😉

 

4.7 回调函数

使用轮询格局来检测异步方法的情事分外辛劳,而且效能不高,有见及此,.NET为
IAsyncResult BeginInvoke(AsyncCallback ,
object)准备了一个回调函数。使用 AsyncCallback
就足以绑定一个措施作为回调函数,回调函数必须是带参数 IAsyncResult
且无重临值的艺术: void AsycnCallbackMethod(IAsyncResult result)
。在BeginInvoke方法成功后,系统就会调用AsyncCallback所绑定的回调函数,最终回调函数中调用
XXX EndInvoke(IAsyncResult result)
就可以终结异步方法,它的回到值类型与寄托的重回值一致。

图片 53😉

 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     }

图片 54😉

可以看看,主线在调用BeginInvoke方法可以继续执行其余命令,而无需再等待了,那无疑比采取轮询方式判断异步方法是否做到更有优势。
在异步方法执行到位后将会调用AsyncCallback所绑定的回调函数,注意一点,回调函数如故是在异步线程中施行,那样就不会潜移默化主线程的运转,那也使用回调函数最值得青昧的地点。
在回调函数中有一个既定的参数IAsyncResult,把IAsyncResult强制转换为AsyncResult后,就足以由此AsyncResult.AsyncDelegate 获取原委托,再使用EndInvoke方法取得总结结果。
运行结果如下:

图片 55

比方想为回调函数传送一些外表音讯,就足以选取BeginInvoke(AsyncCallback,object)的尾声一个参数object,它同意外部向回调函数输入任何类型的参数。只要求在回调函数中行使
AsyncResult.AsyncState 就可以收获object对象。

图片 56😉

 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     }

图片 57😉

运行结果:

图片 58

 

关于I/O线程、SqlCommand多线程查询、PLINQ、定时器与锁的情节将在C#综述揭秘——细说多线程(下)中详尽介绍。
对 .NET 开发有趣味的仇人欢迎出席QQ群:230564952
共同探讨 !

归来目录

C#汇总揭秘

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

细说多线程(上)

细说多线程(下) 前述事务长远剖析委托与事件

 

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

原创文章,转发时请注脚小编及出处

 

 

 

分类:
C#归咎揭秘

相关文章