C#多線程學習 之 線程池[ThreadPool]


在多線程的程序中,經常會出現兩種情況:

一種情況:   應用程序中,線程把大部分的時間花費在等待狀態,等待某個事件發生,然后才能給予響應 
                  這一般使用ThreadPool(線程池)來解決;

另一種情況:線程平時都處於休眠狀態,只是周期性地被喚醒 
                  這一般使用Timer(定時器)來解決;

本篇文章單單講線程池[ThreadPool]

ThreadPool類 MSDN幫助信息: http://msdn.microsoft.com/zh-cn/library/system.threading.threadpool.aspx#Y0

將任務添加進線程池:

ThreadPool.QueueUserWorkItem(new WaitCallback(方法名));

重載

ThreadPool.QueueUserWorkItem(new WaitCallback(方法名), 參數);

因為ThreadPool是靜態類 所以不需要實例化.

 

對於線程池主要的控制有控制線程數大小:

ThreadPool.SetMaxThreads 方法

public static bool SetMaxThreads(
	int workerThreads,
	int completionPortThreads
)

參數:

workerThreads
類型: System.Int32 
線程池中輔助線程的最大數目。
completionPortThreads
類型: System.Int32 
線程池中異步 I/O 線程的最大數目。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Threading;
namespace  多線程池試驗
{
     class  Program
     {
         public  static  void  Main()
         {
             ThreadPool.SetMaxThreads(3, 3);
             for  ( int  i = 0; i < 50; i++)
             {
                 thr t = new  thr();
                 ThreadPool.QueueUserWorkItem( new  WaitCallback(t.ThreadProc), i);
             }
             Console.WriteLine( "斷點測試" );
             Thread.Sleep(100000);
 
             Console.WriteLine( "運行結束" );
         }
 
         public  class  thr
         {
             public  void  ThreadProc( object  i)
             {
                 Console.WriteLine( "Thread["  + i.ToString() + "]" );
                 Thread.Sleep(1000);
             }
         }
     }
}

輸出結果:

image

您會發現 斷點測試 在上面了, 這是什么原因呢?

 

原因:

1. 線程池的啟動和終止不是我們程序所能控制的, 我反正是不知道的, 你如果知道的話 可以發郵件給我 henw@163.com

2. 線程池中的線程執行完之后是沒有返回值的.

總之一句話, 我們不知道線程池他干了什么, 那么我們該怎么解決 任務完成問題呢?

操作系統提供了一種”信號燈”(ManualResetEvent)

ManualResetEvent 允許線程通過發信號互相通信。通常,此通信涉及一個線程在其他線程進行之前必須完成的任務。當一個線程開始一個活動(此活動必須完成后,其他線程才能開始)時,它調用 Reset 以將 ManualResetEvent 置於非終止狀態,此線程可被視為控制 ManualResetEvent。調用 ManualResetEvent 上的 WaitOne 的線程將阻止,並等待信號。當控制線程完成活動時,它調用 Set 以發出等待線程可以繼續進行的信號。並釋放所有等待線程。一旦它被終止,ManualResetEvent 將保持終止狀態(即對 WaitOne 的調用的線程將立即返回,並不阻塞),直到它被手動重置。可以通過將布爾值傳遞給構造函數來控制 ManualResetEvent 的初始狀態,如果初始狀態處於終止狀態,為 true;否則為 false。

詳細見MSDN: http://msdn.microsoft.com/zh-cn/library/system.threading.manualresetevent.aspx

主要使用了

eventX.WaitOne(Timeout.Infinite, true);  阻止當前線程,直到當前 WaitHandle 收到信號為止。

eventX.Set(); 將事件狀態設置為終止狀態,允許一個或多個等待線程繼續。

修改后的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Threading;
namespace  多線程池試驗
{
     class  Program
     {
         public  static  void  Main()
         {
             //新建ManualResetEvent對象並且初始化為無信號狀態
             ManualResetEvent eventX = new  ManualResetEvent( false );
             ThreadPool.SetMaxThreads(3, 3);
             thr t = new  thr(15, eventX);
             for  ( int  i = 0; i < 15; i++)
             {
                 ThreadPool.QueueUserWorkItem( new  WaitCallback(t.ThreadProc), i);
             }
             //等待事件的完成,即線程調用ManualResetEvent.Set()方法
             //eventX.WaitOne  阻止當前線程,直到當前 WaitHandle 收到信號為止。
             eventX.WaitOne(Timeout.Infinite, true );
             Console.WriteLine( "斷點測試" );
             Thread.Sleep(10000);
             Console.WriteLine( "運行結束" );
         }
 
         public  class  thr
         {
             public  thr( int  count,ManualResetEvent mre)
             {
                 iMaxCount = count;
                 eventX = mre;
             }
 
             public  static  int  iCount = 0;
             public  static  int  iMaxCount = 0;
             public  ManualResetEvent eventX;
             public  void  ThreadProc( object  i)
             {
                 Console.WriteLine( "Thread["  + i.ToString() + "]" );
                 Thread.Sleep(2000);
                 //Interlocked.Increment()操作是一個原子操作,作用是:iCount++ 具體請看下面說明
                 //原子操作,就是不能被更高等級中斷搶奪優先的操作。你既然提這個問題,我就說深一點。
                 //由於操作系統大部分時間處於開中斷狀態,
                 //所以,一個程序在執行的時候可能被優先級更高的線程中斷。
                 //而有些操作是不能被中斷的,不然會出現無法還原的后果,這時候,這些操作就需要原子操作。
                 //就是不能被中斷的操作。
                 Interlocked.Increment( ref  iCount);
                 if  (iCount == iMaxCount)
                 {
                     Console.WriteLine( "發出結束信號!" );
                     //將事件狀態設置為終止狀態,允許一個或多個等待線程繼續。
                     eventX.Set();
                 }
             }
         }
     }
}

輸出結果:

image

 

順序正常了.

程序源碼: 多線程池試驗.zip


免責聲明!

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



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