最近做项目的时候,被多线程搞得乱七八糟,脑子都快崩掉。在单步调试的时候发现一个问题,使用线程的abort方法有时并不能如愿跳到异常ThreadAbortException的异常处理中,然后顺利的关闭线程。
在书中找到一个解决方案,特在此分享,使自己以后的遗忘了有据可查。
首先线程不会说停就停,就像它不能立即启动一样,无论以何种方式通知线程停止,工作线程都会处理完当前的事情再在合适的时机退出,以Thread.Abort方法威力,如果线程当前执行的是一段非托管代码,只有当代码回到CLR中时,才会引发ThreadAbortException.注意,即便是在CLR环境中,ThreadAbortException也不会立即发生。
再者,要正确停止线程,不在于调用者采取了什么行动,而更多依赖工作线程是否能主动响应调用者的停止要求。
FCL提供了标准的取消模式:协作式取消。它的机制是:如果线程需要被停止,线程自身会开放接口:Cancelled。线程在工作的同时,还会以某种频率检测Cancelled标识,若检测到,线程就会负责退出。
下面给出示例代码。
CancellationTokenSource cts=new CancellationTokenSource();Thread t=new Thread(()=> { while(true) { if(cts.Token.IsCancellationRequested) { Console.WriteLine("Thread has been stopped"); break; } Thread.Sleep(1000); } });t.Start();Console.ReadLine();cts.Cancel();
调用者使用CancellationTokenSource的Cancel方法通知工作线程退出。工作线程则以大约1000ms的频率一边工作,一边检测是否有外界传入的Cancel信号,若有,则退出。可以看到,在正确停止线程的机制中,真正起到作用的还是线程本身。其中CancellationTokenSource中有一个关键属性Token,它属于一个名为CancellationToken的值类型,此类型提供了一个布尔标识IsCancellationRequested作为取消工作的标识。