http://www.cnblogs.com/henw/archive/2012/01/06/2314870.html
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);
}
}
}
}
|
輸出結果:
您會發現 斷點測試 在上面了, 這是什麽原因呢?
原因:
1. 線程池的啟動和終止不是我們程序所能控制的, 我反正是不知道的, 你如果知道的話 可以發郵件給我 [email protected]
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();
}
}
}
}
}
輸出結果:
順序正常了.
程序源碼: 多線程池試驗.zip
http://www.cnblogs.com/henw/archive/2012/01/06/2314870.html