溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

[.Net線程處理系列]專題二:線程池中的工作者線程

發(fā)布時間:2020-06-27 22:36:07 來源:網(wǎng)絡 閱讀:1120 作者:LearningHard 欄目:編程語言

目錄:

一、上節(jié)補充

二、CLR線程池基礎

三、通過線程池的工作者線程實現(xiàn)異步

四、使用委托實現(xiàn)異步

五、任務

六、小結

 

一、上節(jié)補充

對于Thread類還有幾個常用方法需要說明的。

1.1 Suspend和Resume方法

    這兩個方法在.net Framework 1.0 的時候就支持的方法,他們分別可以掛起線程和恢復掛起的線程。但在.net Framework 2.0以后的版本中這兩個方法都過時了,MSDN的解釋是這樣:

警告:

不要使用 Suspend 和 Resume 方法來同步線程的活動。您無法知道掛起線程時它正在執(zhí)行什么代碼。如果您在安全權限評估期間掛起持有鎖的線程,則 AppDomain中的其他線程可能被阻止。如果您在線程正在執(zhí)行類構造函數(shù)時掛起它,則 AppDomain中嘗試使用該類的其他線程將被阻止。這樣很容易發(fā)生死鎖。

對于這個解釋可能有點抽象吧,讓我們來看看一段代碼可能會清晰點:

  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             // 創(chuàng)建一個線程來測試  
  6.             Thread thread1 = new Thread(TestMethod);        
  7.             thread1.Name = "Thread1";     
  8.             thread1.Start();      
  9.             Thread.Sleep(2000);  
  10.             Console.WriteLine("Main Thread is running");  
  11.             ////int b = 0;  
  12.             ////int a = 3 / b;  
  13.             ////Console.WriteLine(a);  
  14.             thread1.Resume();       
  15.             Console.Read();  
  16.         }  
  17.  
  18.         private static void TestMethod()  
  19.         {       
  20.             Console.WriteLine("Thread: {0} has been suspended!", Thread.CurrentThread.Name);  
  21.         
  22.             //將當前線程掛起  
  23.             Thread.CurrentThread.Suspend();            
  24.             Console.WriteLine("Thread: {0} has been resumed!", Thread.CurrentThread.Name);  
  25.         }  
  26.     } 
 
     在上面這段代碼中thread1線程是在主線程中恢復的,但當主線程發(fā)生異常時,這時候就thread1一直處于掛起狀態(tài),此時thread1所使用的資源就不能釋放(除非強制終止進程),當另外線程需要使用這快資源的時候, 這時候就很可能發(fā)生死鎖現(xiàn)象。

上面一段代碼還存在一個隱患,請看下面一小段代碼:

  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             // 創(chuàng)建一個線程來測試  
  6.             Thread thread1 = new Thread(TestMethod);        
  7.             thread1.Name = "Thread1";     
  8.             thread1.Start();  
  9.             Console.WriteLine("Main Thread is running");  
  10.             thread1.Resume();       
  11.             Console.Read();  
  12.         }  
  13.  
  14.         private static void TestMethod()  
  15.         {       
  16.             Console.WriteLine("Thread: {0} has been suspended!", Thread.CurrentThread.Name);  
  17.             Thread.Sleep(1000);  
  18.  
  19.             //將當前線程掛起  
  20.             Thread.CurrentThread.Suspend();            
  21.             Console.WriteLine("Thread: {0} has been resumed!", Thread.CurrentThread.Name);  
  22.         }  
  23.     } 

    當主線程跑(運行)的太快,做完自己的事情去喚醒thread1時,此時thread1還沒有掛起而起喚醒thread1,此時就會出現(xiàn)異常了。并且上面使用的Suspend和Resume方法,編譯器已經(jīng)出現(xiàn)警告了,提示這兩個方法已經(jīng)過時, 所以在我們平時使用中應該盡量避免

1.2 Abort和 Interrupt方法

Abort方法和Interrupt都是用來終止線程的,但是兩者還是有區(qū)別的。

1、他們拋出的異常不一樣,Abort 方法拋出的異常是ThreadAbortException, Interrupt拋出的異常為ThreadInterruptedException

2、調(diào)用interrupt方法的線程之后可以被喚醒,然而調(diào)用Abort方法的線程就直接被終止不能被喚醒的。

下面一段代碼是演示Abort方法的使用

  1. using System;  
  2. using System.Threading;  
  3.  
  4. namespace ConsoleApplication1  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             Thread abortThread = new Thread(AbortMethod);  
  11.             abortThread.Name = "Abort Thread";  
  12.             abortThread.Start();  
  13.             Thread.Sleep(1000);  
  14.             try 
  15.             {  
  16.                 abortThread.Abort();       
  17.             }  
  18.             catch   
  19.             {  
  20.                 Console.WriteLine("{0} Exception happen in Main Thread", Thread.CurrentThread.Name);  
  21.                 Console.WriteLine("{0} Status is:{1} In Main Thread ", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);  
  22.             }  
  23.             finally 
  24.             {  
  25.                 Console.WriteLine("{0} Status is:{1} In Main Thread ", abortThread.Name, abortThread.ThreadState);  
  26.             }  
  27.  
  28.             abortThread.Join();  
  29.             Console.WriteLine("{0} Status is:{1} ", abortThread.Name, abortThread.ThreadState);  
  30.             Console.Read();  
  31.              
  32.         }  
  33.  
  34.         private static void AbortMethod()  
  35.         {  
  36.             try 
  37.             {  
  38.                 Thread.Sleep(5000);  
  39.             }  
  40.             catch(Exception e)  
  41.             {  
  42.                 Console.WriteLine(e.GetType().Name);  
  43.                 Console.WriteLine("{0} Exception happen In Abort Thread", Thread.CurrentThread.Name);  
  44.                 Console.WriteLine("{0} Status is:{1} In Abort Thread ", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);  
  45.             }  
  46.             finally 
  47.             {  
  48.                 Console.WriteLine("{0} Status is:{1} In Abort Thread", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);  
  49.             }  
  50.         }  
  51.     } 
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

    從運行結果可以看出,調(diào)用Abort方法的線程引發(fā)的異常類型為ThreadAbortException, 以及異常只會在 調(diào)用Abort方法的線程中發(fā)生,而不會在主線程中拋出,并且調(diào)用Abort方法后線程的狀態(tài)不是立即改變?yōu)锳borted狀態(tài),而是從AbortRequested->Aborted

Interrupt方法:

  1. using System;  
  2. using System.Threading;  
  3.  
  4. namespace ConsoleApplication1  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         { Thread interruptThread = new Thread(AbortMethod);  
  10.             interruptThread.Name = "Interrupt Thread";  
  11.             interruptThread.Start();    
  12.             interruptThread.Interrupt();       
  13.              
  14.             interruptThread.Join();  
  15.             Console.WriteLine("{0} Status is:{1} ", interruptThread.Name, interruptThread.ThreadState);  
  16.             Console.Read();       
  17.         }  
  18.  
  19.         private static void AbortMethod()  
  20.         {  
  21.             try 
  22.             {  
  23.                 Thread.Sleep(5000);  
  24.             }  
  25.             catch(Exception e)  
  26.             {  
  27.                 Console.WriteLine(e.GetType().Name);  
  28.                 Console.WriteLine("{0} Exception happen In Interrupt Thread", Thread.CurrentThread.Name);  
  29.                 Console.WriteLine("{0} Status is:{1} In Interrupt Thread ", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);  
  30.             }  
  31.             finally 
  32.             {  
  33.                 Console.WriteLine("{0} Status is:{1} In Interrupt Thread", Thread.CurrentThread.Name, Thread.CurrentThread.ThreadState);  
  34.             }  
  35.         }  
  36.     }  
 運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

    從結果中可以得到,調(diào)用Interrupt方法拋出的異常為:ThreadInterruptException, 以及當調(diào)用Interrupt方法后線程的狀態(tài)應該是中斷的, 但是從運行結果看此時的線程因為了Join,Sleep方法而喚醒了線程,為了進一步解釋調(diào)用Interrupt方法的線程可以被喚醒, 我們可以在線程執(zhí)行的方法中運用循環(huán),如果線程可以喚醒,則輸出結果中就一定會有循環(huán)的部分,然而調(diào)用Abort方法線程就直接終止,就不會有循環(huán)的部分,下面代碼相信大家看后肯定會更加理解兩個方法的區(qū)別的:

  1. using System;  
  2. using System.Threading;  
  3.  
  4. namespace ConsoleApplication2  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             Thread thread1 = new Thread(TestMethod);  
  11.             thread1.Start();  
  12.             Thread.Sleep(100);  
  13.  
  14.             thread1.Interrupt();  
  15.             Thread.Sleep(3000);  
  16.             Console.WriteLine("after finnally block, the Thread1 status is:{0}", thread1.ThreadState);  
  17.             Console.Read();  
  18.         }  
  19.         private static void TestMethod()  
  20.         {  
  21.               
  22.             for (int i = 0; i < 4; i++)  
  23.             {  
  24.                 try 
  25.                 {  
  26.                     Thread.Sleep(2000);  
  27.                     Console.WriteLine("Thread is Running");  
  28.                 }  
  29.                 catch (Exception e)  
  30.                 {  
  31.                     if (e != null)  
  32.                     {  
  33.                         Console.WriteLine("Exception {0} throw ", e.GetType().Name);  
  34.                     }  
  35.                 }  
  36.                 finally 
  37.                 {  
  38.                     Console.WriteLine("Current Thread status is:{0} ", Thread.CurrentThread.ThreadState);  
  39.                 }  
  40.             }  
  41.         }  
  42.     }  
運行結果為:[.Net線程處理系列]專題二:線程池中的工作者線程

如果把上面的 thread1.Interrupt();改為 thread1.Abort(); 運行結果為:[.Net線程處理系列]專題二:線程池中的工作者線程

 二、線程池基礎

    首先,創(chuàng)建和銷毀線程是一個要耗費大量時間的過程,另外,太多的線程也會浪費內(nèi)存資源,所以通過Thread類來創(chuàng)建過多的線程反而有損于性能,為了改善這樣的問題 ,.net中就引入了線程池。

    線程池形象的表示就是存放應用程序中使用的線程的一個集合(就是放線程的地方,這樣線程都放在一個地方就好管理了)。CLR初始化時,線程池中是沒有線程的,在內(nèi)部, 線程池維護了一個操作請求隊列,當應用程序想執(zhí)行一個異步操作時,就調(diào)用一個方法,就將一個任務放到線程池的隊列中,線程池中代碼從隊列中提取任務,將這個任務委派給一個線程池線程去執(zhí)行,當線程池線程完成任務時,線程不會被銷毀,而是返回到線程池中,等待響應另一個請求。由于線程不被銷毀, 這樣就可以避免因為創(chuàng)建線程所產(chǎn)生的性能損失。

注意:通過線程池創(chuàng)建的線程默認為后臺線程,優(yōu)先級默認為Normal.

三、通過線程池的工作者線程實現(xiàn)異步

3.1 創(chuàng)建工作者線程的方法

public static bool QueueUserWorkItem (WaitCallback callBack);

public static bool QueueUserWorkItem(WaitCallback callback, Object state);

這兩個方法向線程池的隊列添加一個工作項(work item)以及一個可選的狀態(tài)數(shù)據(jù)。然后,這兩個方法就會立即返回。

工作項其實就是由callback參數(shù)標識的一個方法,該方法將由線程池線程執(zhí)行。同時寫的回調(diào)方法必須匹配System.Threading.WaitCallback委托類型,定義為:

public delegate void WaitCallback(Object state);

下面演示如何通過線程池線程來實現(xiàn)異步調(diào)用:

  1. using System;  
  2. using System.Threading;  
  3.  
  4. namespace ThreadPoolUse  
  5. {  
  6.     class Program  
  7.     {  
  8.         static void Main(string[] args)  
  9.         {  
  10.             // 設置線程池中處于活動的線程的最大數(shù)目  
  11.             // 設置線程池中工作者線程數(shù)量為1000,I/O線程數(shù)量為1000  
  12.             ThreadPool.SetMaxThreads(1000, 1000);  
  13.             Console.WriteLine("Main Thread: queue an asynchronous method");  
  14.             PrintMessage("Main Thread Start");  
  15.  
  16.             // 把工作項添加到隊列中,此時線程池會用工作者線程去執(zhí)行回調(diào)方法  
  17.             ThreadPool.QueueUserWorkItem(asyncMethod);  
  18.             Console.Read();  
  19.         }  
  20.  
  21.         // 方法必須匹配WaitCallback委托  
  22.         private static void asyncMethod(object state)  
  23.         {  
  24.             Thread.Sleep(1000);  
  25.             PrintMessage("Asynchoronous Method");  
  26.             Console.WriteLine("Asynchoronous thread has worked ");  
  27.         }  
  28.  
  29.         // 打印線程池信息  
  30.         private static void PrintMessage(String data)  
  31.         {  
  32.             int workthreadnumber;  
  33.             int iothreadnumber;  
  34.  
  35.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  36.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  37.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  38.  
  39.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  40.                 data,  
  41.                 Thread.CurrentThread.ManagedThreadId,   
  42.                 Thread.CurrentThread.IsBackground.ToString(),  
  43.                 workthreadnumber.ToString(),  
  44.                 iothreadnumber.ToString());  
  45.         }  
  46.     }  
運行結果:   [.Net線程處理系列]專題二:線程池中的工作者線程

從結果中可以看出,線程池中的可用的工作者線程少了一個,用去執(zhí)行回調(diào)方法了。

ThreadPool.QueueUserWorkItem(WaitCallback callback,Object state) 方法可以把object對象作為參數(shù)傳送到回調(diào)函數(shù)中,使用和ThreadPool.QueueUserWorkItem(WaitCallback callback)的使用和類似,這里就不列出了。

3.2 協(xié)作式取消

    .net Framework提供了取消操作的模式, 這個模式是協(xié)作式的。為了取消一個操作,首先必須創(chuàng)建一個System.Threading.CancellationTokenSource對象。

下面代碼演示了協(xié)作式取消的使用,主要實現(xiàn)當用戶在控制臺敲下回車鍵后就停止數(shù)數(shù)方法。

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Threading;  
  6.  
  7. namespace ConsoleApplication3  
  8. {  
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             ThreadPool.SetMaxThreads(1000, 1000);  
  14.             Console.WriteLine("Main thread run");      
  15.             PrintMessage("Start");  
  16.             Run();  
  17.             Console.ReadKey();  
  18.         }  
  19.  
  20.         private static void Run()  
  21.         {  
  22.             CancellationTokenSource cts = new CancellationTokenSource();  
  23.  
  24.             // 這里用Lambda表達式的方式和使用委托的效果一樣的,只是用了Lambda后可以少定義一個方法。  
  25.             // 這在這里就是讓大家明白怎么lambda表達式如何由委托轉變的  
  26.             ////ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));  
  27.  
  28.             ThreadPool.QueueUserWorkItem(callback, cts.Token);  
  29.  
  30.             Console.WriteLine("Press Enter key to cancel the operation\n");  
  31.             Console.ReadLine();  
  32.  
  33.             // 傳達取消請求  
  34.             cts.Cancel();  
  35.         }  
  36.           
  37.         private static void callback(object state)  
  38.         {  
  39.             Thread.Sleep(1000);  
  40.             PrintMessage("Asynchoronous Method Start");  
  41.             CancellationToken token =(CancellationToken)state;      
  42.             Count(token, 1000);  
  43.         }  
  44.  
  45.         // 執(zhí)行的操作,當受到取消請求時停止數(shù)數(shù)  
  46.         private static void Count(CancellationToken token,int countto)  
  47.         {  
  48.             for (int i = 0; i < countto; i++)  
  49.             {  
  50.                 if (token.IsCancellationRequested)  
  51.                 {  
  52.                     Console.WriteLine("Count is canceled");  
  53.                     break;  
  54.                 }  
  55.  
  56.                 Console.WriteLine(i);  
  57.                 Thread.Sleep(300);  
  58.             }  
  59.               
  60.             Console.WriteLine("Cout has done");         
  61.         }  
  62.  
  63.         // 打印線程池信息  
  64.         private static void PrintMessage(String data)  
  65.         {  
  66.             int workthreadnumber;  
  67.             int iothreadnumber;  
  68.  
  69.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  70.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  71.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  72.  
  73.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  74.                 data,  
  75.                 Thread.CurrentThread.ManagedThreadId,  
  76.                 Thread.CurrentThread.IsBackground.ToString(),  
  77.                 workthreadnumber.ToString(),  
  78.                 iothreadnumber.ToString());  
  79.         }  
  80.     }  
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

 四、使用委托實現(xiàn)異步

    通過調(diào)用ThreadPool的QueueUserWorkItem方法來來啟動工作者線程非常方便,但委托WaitCallback指向的是帶有一個參數(shù)的無返回值的方法,如果我們實際操作中需要有返回值,或者需要帶有多個參數(shù), 這時通過這樣的方式就難以實現(xiàn), 為了解決這樣的問題,我們可以通過委托來建立工作這線程,

下面代碼演示了使用委托如何實現(xiàn)異步:

  1. using System;  
  2. using System.Threading;  
  3.  
  4. namespace Delegate  
  5. {  
  6.     class Program  
  7.     {  
  8.         // 使用委托的實現(xiàn)的方式是使用了異步變成模型APM(Asynchronous Programming Model)  
  9.         // 自定義委托  
  10.         private delegate string MyTestdelegate();  
  11.  
  12.         static void Main(string[] args)  
  13.         {  
  14.             ThreadPool.SetMaxThreads(1000, 1000);  
  15.             PrintMessage("Main Thread Start");  
  16.  
  17.             //實例化委托  
  18.             MyTestdelegate testdelegate = new MyTestdelegate(asyncMethod);  
  19.  
  20.             // 異步調(diào)用委托  
  21.             IAsyncResult result = testdelegate.BeginInvoke(nullnull);  
  22.  
  23.             // 獲取結果并打印出來  
  24.             string returndata = testdelegate.EndInvoke(result);  
  25.             Console.WriteLine(returndata);  
  26.  
  27.             Console.ReadLine();  
  28.         }  
  29.         private static string asyncMethod()  
  30.         {  
  31.             Thread.Sleep(1000);  
  32.             PrintMessage("Asynchoronous Method");  
  33.             return "Method has completed";  
  34.         }  
  35.  
  36.         // 打印線程池信息  
  37.         private static void PrintMessage(String data)  
  38.         {  
  39.             int workthreadnumber;  
  40.             int iothreadnumber;  
  41.  
  42.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  43.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  44.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  45.  
  46.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  47.                 data,  
  48.                 Thread.CurrentThread.ManagedThreadId,  
  49.                 Thread.CurrentThread.IsBackground.ToString(),  
  50.                 workthreadnumber.ToString(),  
  51.                 iothreadnumber.ToString());  
  52.         }  
  53.     }  
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

 五、任務

同樣 任務的引入也是為了解決通過ThreadPool.QueueUserWorkItem中限制的問題,

下面代碼演示通過任務來實現(xiàn)異步:

5.1 使用任務來實現(xiàn)異步

  1. using System;  
  2. using System.Threading;  
  3. using System.Threading.Tasks;  
  4.  
  5. namespace TaskUse  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             ThreadPool.SetMaxThreads(1000, 1000);  
  12.             PrintMessage("Main Thread Start");  
  13.             // 調(diào)用構造函數(shù)創(chuàng)建Task對象,  
  14.             Task<int> task = new Task<int>(n => asyncMethod((int)n), 10);  
  15.  
  16.             // 啟動任務   
  17.             task.Start();  
  18.             // 等待任務完成  
  19.             task.Wait();  
  20.             Console.WriteLine("The Method result is: "+task.Result);  
  21.  
  22.             Console.ReadLine();  
  23.         }  
  24.  
  25.         private static int asyncMethod(int n)  
  26.         {  
  27.             Thread.Sleep(1000);  
  28.             PrintMessage("Asynchoronous Method");  
  29.  
  30.             int sum = 0;  
  31.             for (int i = 1; i < n; i++)  
  32.             {  
  33.                 // 如果n太大,使用checked使下面代碼拋出異常  
  34.                 checked 
  35.                 {  
  36.                     sum += i;  
  37.                 }  
  38.             }  
  39.  
  40.             return sum;  
  41.         }  
  42.  
  43.         // 打印線程池信息  
  44.         private static void PrintMessage(String data)  
  45.         {  
  46.             int workthreadnumber;  
  47.             int iothreadnumber;  
  48.  
  49.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  50.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  51.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  52.  
  53.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  54.                 data,  
  55.                 Thread.CurrentThread.ManagedThreadId,  
  56.                 Thread.CurrentThread.IsBackground.ToString(),  
  57.                 workthreadnumber.ToString(),  
  58.                 iothreadnumber.ToString());  
  59.         }  
  60.     }  
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

5.2 取消任務

如果要取消任務, 同樣可以使用一個CancellationTokenSource對象來取消一個Task.

下面代碼演示了如何來取消一個任務:

  1. using System;  
  2. using System.Threading;  
  3. using System.Threading.Tasks;  
  4.  
  5. namespace TaskUse  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             ThreadPool.SetMaxThreads(1000, 1000);  
  12.             PrintMessage("Main Thread Start");  
  13.             CancellationTokenSource cts = new CancellationTokenSource();  
  14.  
  15.             // 調(diào)用構造函數(shù)創(chuàng)建Task對象,將一個CancellationToken傳給Task構造器從而使Task和CancellationToken關聯(lián)起來  
  16.             Task<int> task = new Task<int>(n => asyncMethod(cts.Token, (int)n), 10);  
  17.  
  18.             // 啟動任務   
  19.             task.Start();  
  20.  
  21.             // 延遲取消任務  
  22.             Thread.Sleep(3000);  
  23.  
  24.             // 取消任務  
  25.             cts.Cancel();  
  26.             Console.WriteLine("The Method result is: " + task.Result);  
  27.             Console.ReadLine();  
  28.         }  
  29.  
  30.         private static int asyncMethod(CancellationToken ct, int n)  
  31.         {  
  32.             Thread.Sleep(1000);  
  33.             PrintMessage("Asynchoronous Method");  
  34.  
  35.             int sum = 0;  
  36.             try 
  37.             {  
  38.                 for (int i = 1; i < n; i++)  
  39.                 {  
  40.                     // 當CancellationTokenSource對象調(diào)用Cancel方法時,  
  41.                     // 就會引起OperationCanceledException異常  
  42.                     // 通過調(diào)用CancellationToken的ThrowIfCancellationRequested方法來定時檢查操作是否已經(jīng)取消,  
  43.                     // 這個方法和CancellationToken的IsCancellationRequested屬性類似  
  44.                     ct.ThrowIfCancellationRequested();  
  45.                     Thread.Sleep(500);  
  46.                     // 如果n太大,使用checked使下面代碼拋出異常  
  47.                     checked 
  48.                     {  
  49.                         sum += i;  
  50.                     }  
  51.                 }  
  52.             }  
  53.             catch (Exception e)  
  54.             {  
  55.                 Console.WriteLine("Exception is:" + e.GetType().Name);  
  56.                 Console.WriteLine("Operation is Canceled");  
  57.             }  
  58.  
  59.             return sum;  
  60.         }  
  61.  
  62.         // 打印線程池信息  
  63.         private static void PrintMessage(String data)  
  64.         {  
  65.             int workthreadnumber;  
  66.             int iothreadnumber;  
  67.  
  68.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  69.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  70.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  71.  
  72.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  73.                 data,  
  74.                 Thread.CurrentThread.ManagedThreadId,  
  75.                 Thread.CurrentThread.IsBackground.ToString(),  
  76.                 workthreadnumber.ToString(),  
  77.                 iothreadnumber.ToString());  
  78.         }  
  79.     }  
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

 5.3 任務工廠

同樣可以通過任務工廠TaskFactory類型來實現(xiàn)異步操作。

  1. using System;  
  2. using System.Threading;  
  3. using System.Threading.Tasks;  
  4.  
  5. namespace TaskFactory  
  6. {  
  7.     class Program  
  8.     {  
  9.         static void Main(string[] args)  
  10.         {  
  11.             ThreadPool.SetMaxThreads(1000, 1000);  
  12.             Task.Factory.StartNew(() => PrintMessage("Main Thread"));   
  13.             Console.Read();  
  14.         }  
  15.         // 打印線程池信息  
  16.         private static void PrintMessage(String data)  
  17.         {  
  18.             int workthreadnumber;  
  19.             int iothreadnumber;  
  20.  
  21.             // 獲得線程池中可用的線程,把獲得的可用工作者線程數(shù)量賦給workthreadnumber變量  
  22.             // 獲得的可用I/O線程數(shù)量給iothreadnumber變量  
  23.             ThreadPool.GetAvailableThreads(out workthreadnumber, out iothreadnumber);  
  24.  
  25.             Console.WriteLine("{0}\n CurrentThreadId is {1}\n CurrentThread is background :{2}\n WorkerThreadNumber is:{3}\n IOThreadNumbers is: {4}\n",  
  26.                 data,  
  27.                 Thread.CurrentThread.ManagedThreadId,  
  28.                 Thread.CurrentThread.IsBackground.ToString(),  
  29.                 workthreadnumber.ToString(),  
  30.                 iothreadnumber.ToString());  
  31.         }  
  32.     }  
運行結果:[.Net線程處理系列]專題二:線程池中的工作者線程

 六、小結

    講到這里CLR的工作者線程大致講完了,希望也篇文章可以讓大家對線程又有進一步的理解。在后面的一篇線程系列將談談CLR線程池的I/O線程。

 

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI