[C#.NET][Thread] 執行緒的順序啟動 - WaitHandle.WaitAll 方法
WaitHandle.WaitAll 跟Thread.Join很像,都是執行緒等待,在功能上就是執行緒的順序啟動,如同我之前寫過的 [Thread] 執行緒的順序啟動 - Thread.Join方法,實作過程很簡單只需要注意以下兩點
1.WaitHandle是一個抽像類別所以我們得實體化它的子類別,也就是 ManualResetEvent 類別 或AutoResetEvent 類別,如下所示
static WaitHandle[] waitHandles = new WaitHandle[]
{
new AutoResetEvent(false),
new AutoResetEvent(false)
};
2.再來,看一下多載清單,WaitHandle.WaitAll方法只收WaitHandle[]參數
接下來則演練如何實作WaitHandle,我用一個類別將我要的資訊擺進去
public class Calculator
{
public string Name { get; set; }
public long Result { get; set; }
private AutoResetEvent _WaitHandle;
public AutoResetEvent WaitHandle
{
get { return _WaitHandle; }
set { _WaitHandle = value; }
}
}
用戶端的呼叫
static WaitHandle[] waitHandles = null;
static object _lock = new object();
static void Main(string[] args)
{
DateTime dt = DateTime.Now;
Console.WriteLine("進入主執行緒");
//建立集合
List<Calculator> calculator = new List<Calculator>()
{
new Calculator{Result=0,WaitHandle=new AutoResetEvent(false),Name="NO.1"},
new Calculator{Result=0,WaitHandle=new AutoResetEvent(false),Name="NO.2"}
};
//建立WaitHandle陣列,因為WaitHandle.WaitAll只收陣列
waitHandles = new WaitHandle[calculator.Count];
for (int i = 0; i < calculator.Count; i++)
{
waitHandles[i] = calculator[i].WaitHandle;
}
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), calculator[0]);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), calculator[1]);
//等待這兩隻執行緒完成工作
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("子執行緒完成,花費時間 ={0})", (DateTime.Now - dt).TotalMilliseconds);
Console.ReadKey();
}
模擬大量運算工作
static void DoTask(Object state)
{
lock (_lock)
{
if (_isTimeOut)
return;
Calculator calculator = (Calculator)state;
Console.WriteLine("{0} 進入子執行緒", calculator.Name);
AutoResetEvent reset = calculator.WaitHandle;
for (long i = 0; i < 1000000000; i++)
{
calculator.Result++;
}
Console.WriteLine("{0} 計算結果 :{1}", calculator.Name, calculator.Result.ToString());
Console.WriteLine("{0} 離開子執行緒", calculator.Name);
reset.Set();
}
}
執行結果就跟我想的一樣,因為 WaitHandle.WaitAll(waitHandles)的關係,主執行緒乖乖的等待所有執行緒完成工作,
WaitHandle.WaitAll還可以設定等待時間,我們把WaitHandle.WaitAll(waitHandles)改成WaitHandle.WaitAll(waitHandles,2000),表示主執行緒願意等子執行緒2秒。
因為ThreadPool沒有Abort方法所以,我加一個變數_isTimeOut旗標,用來判斷執行緒是否結束工作。
再改裝一下程式碼,
static bool _isTimeOut=false; static void Main(string[] args) { …略 //等待這兩隻執行緒完成工作 WaitHandle.WaitAll(waitHandles,2000); _isTimeOut = true; Console.WriteLine("子執行緒完成,花費時間 ={0})", (DateTime.Now - dt).TotalMilliseconds); Console.ReadKey(); }
static void DoTask(Object state) { lock (_lock) { if (_isTimeOut) return; …略 for (longi = 0; i < 1000000000; i++) { //離開子執行緒旗標 if (_isTimeOut) { Console.WriteLine("{0} 計算結果 :{1}", calculator.Name, calculator.Result.ToString()); Console.WriteLine("{0} 離開子執行緒", calculator.Name); return; } calculator.Result++; } …略 } }
執行結果,主執行緒等了2秒後,就不想等了,於是就叫子執行緒停下他的工作。
WaitHandle.WaitAny方法就是等待任何一隻執行緒完成工作
static void Main(string[] args)
{
…略
//等待任一隻執行緒完成工作
int index = WaitHandle.WaitAny(waitHandles);
_isTimeOut = true;
Console.WriteLine("子執行緒完成,花費時間 ={0})", (DateTime.Now - dt).TotalMilliseconds);
Console.ReadKey();
}
執行結果:可以觀察出當任一執行緒完成工作後則離開所有子執行緒