C# 多執行緒學習系列四之取消、超時子執行緒操作
1、簡介
雖然ThreadPool、Thread能開啟子執行緒將一些任務交給子執行緒去承擔,但是很多時候,因為某種原因,比如子執行緒發生異常、或者子執行緒的業務邏輯不符合我們的預期,那麼這個時候我們必須關閉它,而不是讓它繼續執行,消耗資源.讓CPU不在把時間和資源花在沒有意義的程式碼上.
2、主執行緒取消所有子執行緒執行的簡單程式碼演示和原理分析
(1)、程式碼演示
static void Main(string[] args) { //顯示定義一個取消輔助執行緒的操作 CancellationTokenSource ctsToken = newCancellationTokenSource(); ThreadPool.QueueUserWorkItem(o => EoworkOne(ctsToken.Token)); ThreadPool.QueueUserWorkItem(o => EoworkTwo(ctsToken.Token)); ctsToken.Cancel(); Console.Read(); } /// <summary> /// 輔助執行緒一/// </summary> /// <param name="token"></param> static void EoworkOne(CancellationToken token) { //判斷主執行緒是否呼叫了CancellationTokenSource例項的Cancel方法 //相當於判斷主執行緒是否傳遞給輔助執行緒一一個取消標記 if (token.IsCancellationRequested) {//如果主執行緒傳遞給輔助執行緒一一個取消操作標記,執行下面的程式碼 Console.WriteLine("主執行緒呼叫了Cancel方法,所以輔助執行緒一獲取了主執行緒取消輔助執行緒一的標記,但是並不會真正的關閉當前執行緒"); Console.WriteLine("輔助執行緒一執行return操作,自己顯示的退出,那麼接下去的方法都不會被執行"); return; } } /// <summary> /// 輔助執行緒二 /// </summary> /// <param name="token"></param> static void EoworkTwo(CancellationToken token) { //判斷主執行緒是否呼叫了CancellationTokenSource例項的Cancel方法 //相當於判斷主執行緒是否傳遞給輔助執行緒一一個取消標記 if (token.IsCancellationRequested) { //如果主執行緒傳遞給輔助執行緒一一個取消操作標記,執行下面的程式碼 Console.WriteLine("主執行緒呼叫了Cancel方法,所以輔助執行緒二獲取了主執行緒取消輔助執行緒二的標記,但是並不會真正的關閉當前執行緒"); } //因為當主執行緒傳遞給輔助執行緒二一個取消標記,但是上面的if語句塊,並沒有執行return操作,所以下面的語句還是會繼續執行 Console.WriteLine("輔助執行緒二獲得取消標記操作後,並沒有執行顯示的return操作,所以輔助執行緒二繼續執行"); }
(2)、原理分析
第一步:建立一個CancellationTokenSource物件例項,該物件包含了所有關於取消子執行緒有關的所有狀態
CancellationTokenSource ctsToken = new CancellationTokenSource();
第二步:將CancellationTokenSource物件例項的CancellationToken物件例項傳遞給需要進行取消操作的所有子執行緒.並且可以通過這個CancellationToken物件例項關聯到CancellationTokenSource物件例項.
ThreadPool.QueueUserWorkItem(o => EoworkOne(ctsToken.Token));
ThreadPool.QueueUserWorkItem(o => EoworkTwo(ctsToken.Token));
第三步:當主執行緒呼叫CancellationTokenSource物件例項的Cancel方法,所有的子執行緒通過呼叫CancellationToken物件例項的IsCancellationRequested屬性,該屬性定時去獲取初始執行緒(主執行緒)是否執行了CancellationTokenSource物件例項的Cancel方法,如果呼叫了,該屬性為true。這時可以理解為子執行緒到主執行緒的取消訊號,可以通過呼叫return方法來終止子執行緒的操作.
//判斷主執行緒是否呼叫了CancellationTokenSource例項的Cancel方法 //相當於判斷主執行緒是否傳遞給輔助執行緒一一個取消標記 if (token.IsCancellationRequested) { //如果主執行緒傳遞給輔助執行緒一一個取消操作標記,執行下面的程式碼 Console.WriteLine("主執行緒呼叫了Cancel方法,所以輔助執行緒一獲取了主執行緒取消輔助執行緒一的標記,但是並不會真正的關閉當前執行緒"); Console.WriteLine("輔助執行緒一執行return操作,自己顯示的退出,那麼接下去的方法都不會被執行"); return; }
3、如果建立一個不能被取消的子執行緒
通過給子執行緒傳遞一個CancellationToken.None例項,該子執行緒無法被取消,原因很簡單,CancellationToken.None例項沒有關聯的CancellationTokenSource物件例項,所以無法呼叫Cancel方法顯示取消.所以子執行緒呼叫token.IsCancellationRequested屬性,該屬性永遠為false.呼叫token.CanBeCanceled屬性也為false.
static void Main(string[] args) { ThreadPool.QueueUserWorkItem(o => EoworkOne(CancellationToken.None)); Console.Read(); } /// <summary> /// 輔助執行緒一 /// </summary> /// <param name="token"></param> static void EoworkOne(CancellationToken token) { if (token.IsCancellationRequested) { //永遠無法執行 } Console.WriteLine("輔助執行緒一能被取消嗎?{0}",token.CanBeCanceled?"能":"不能"); Console.WriteLine("通過CancellationToken.None例項建立的子執行緒無法被取消"); }
4、初始執行緒(主執行緒)呼叫給CancellationTokenSource物件例項的Cancel方法添加回調函式