1. 程式人生 > >C# 多執行緒學習系列四之取消、超時子執行緒操作

C# 多執行緒學習系列四之取消、超時子執行緒操作

1、簡介

雖然ThreadPool、Thread能開啟子執行緒將一些任務交給子執行緒去承擔,但是很多時候,因為某種原因,比如子執行緒發生異常、或者子執行緒的業務邏輯不符合我們的預期,那麼這個時候我們必須關閉它,而不是讓它繼續執行,消耗資源.讓CPU不在把時間和資源花在沒有意義的程式碼上.

 

2、主執行緒取消所有子執行緒執行的簡單程式碼演示和原理分析

(1)、程式碼演示

        static void Main(string[] args)
        {
            //顯示定義一個取消輔助執行緒的操作
            CancellationTokenSource ctsToken = new
CancellationTokenSource(); 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方法添加回調函式