【轉】改善C#程序的建議7:正確停止線程


開發者總嘗試對自己的代碼有更多的控制。“讓那個還在工作的線程馬上停止下來”就是諸多要求中的一種。然而事與願違,這里面至少存在兩個問題:

第一個問題是:正如線程不能立即啟動一樣,線程也並不能說停就停。無論采用何種方式通知工作線程需要停止,工作線程都會忙完手頭最緊要的活,然后在它覺得合適的時候退出。以最傳統的Thread.Abort方法為例,如果線程當前正在執行的是一段非托管代碼,那么CLR就不會拋出ThreadAbortException,只有當代碼繼續回到CLR中時,才會引發ThreadAbortException。當然,即便是在CLR環境中,ThreadAbortException也不會立即引發。

其次,正確停止線程,不在於調用者采取了什么行為(如最開始的Thread.Abort()方法),而更多依賴於工作線程是否能主動響應調用者的停止請求。大體機制是,如果線程需要被停止,那么線程自身就得負責開放給調用者這樣的接口:Cancled,然后線程在工作的同時,還得以某種頻率檢測Cancled標識,若檢測到Cancled,線程自己負責退出。

FCL現在為我們提供了標准的取消模式:協作式取消(Cooperative Cancellation)。協作式取消的機制就是上文提到的機制。下面是一個最基礎的協作式取消的樣例:

CancellationTokenSource cts = new CancellationTokenSource();
Thread t
= new Thread(() =>
{
while ( true )
{
if (cts.Token.IsCancellationRequested)
{
Console.WriteLine(
" 線程被終止! " );
break ;
}
Console.WriteLine(DateTime.Now.ToString());
Thread.Sleep(
1000 );
}
});
t.Start();
Console.ReadLine();
cts.Cancel();

調用者使用CancellationTokenSource的Cancle方法通知工作線程退出。工作線程則以大致1000毫秒的頻率一邊工作,一邊檢查是否有外界傳入進來的Cancel信號。若有這樣的信號,則負責退出。可以看到,在正確停止線程的機制中,真正起到主要作用的是線程本身。樣例中的工作代碼比較簡單,不過也足以說明問題。更復雜的計算式的工作,也應該以這樣的一種方式,妥善而正確地處理退出。

協作式取消中的關鍵類型是CancellationTokenSource。它有一個關鍵屬性Token,Token是一個名為CancellationToken的值類型。CancellationToken繼而進一步提供了布爾值的屬性IsCancellationRequested作為需要取消工作的標識。CancellationToken還有一個方法尤其值得注意,那就是Register方法。它負責傳遞一個Action委托,在線程停止的時候被回調,使用方法如:

cts.Token.Register(() =>
{
Console.WriteLine(
" 工作線程被終止了。 " );
});

本建議中的例子使用Thread進行了演示,使用ThreadPool也是一樣的模式,這里就不再贅述。后面我們還會講到任務Task,它依賴於CancellationTokenSource和CancellationToken完成了所有的取消控制。   

 微信掃一掃,關注最課程(www.zuikc.com),獲取更多我的文章,獲取軟件開發每日一練

之前的話題:

改善C#程序的建議6:在線程同步中使用信號量
改善C#程序的建議5:引用類型賦值為null與加速垃圾回收
改善C#程序的建議4:C#中標准Dispose模式的實現
改善C#程序的建議3:在C#中選擇正確的集合進行編碼
改善C#程序的建議2:C#中dynamic的正確用法
改善C#程序的建議1:非用ICloneable不可的理由

================================== 原文鏈接==================================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM