最近做項目的時候,被多線程搞得亂七八糟,腦子都快崩掉。在單步調試的時候發現一個問題,使用線程的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作為取消工作的標識。