close
今天來複習一下執行緒, 先前有一些觀念錯誤: 關於暫停/關閉執行緒Suspend, Terminate
不該踩到地雷, 我一個都沒錯過@@
1. 本範例示範如何開一個worker執行緒, 呼叫Start開始不斷執行Job內容, 且不影響原本的主執行緒
2. 要暫停一個執行緒不建議使用Thread.Suspend, 這會讓你不曉得在你呼叫Suspend
當下該執行緒在幹甚麼;更準確地說, 你會不曉得worker在Job中已經
完成多少(停在Job中的哪個階段)
3. 不要使用Terminate, 建議使用Join
3. 透過ManualResetEvent搭配WaitOne 方法, 可以讓你更精準控制: 暫停, 繼續, 以及停止執行緒
public class Worker
{
/* Initializes a new instance of the ManualResetEvent class
* with a Boolean value indicating whether to set the initial state to signaled.
*/
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Job()
{
int cnt = 0;
while (true)
{
/* 封鎖目前執行緒, 直到waitHandle收到通知,
* Timeout.Infinite表示無限期等候
*/
_pauseEvent.WaitOne(Timeout.Infinite);
/* return true if the current instance receives a signal.
* If the current instance is never signaled, WaitOne never returns
*/
if(_shutdownEvent.WaitOne(0))
break;
/* if (_shutdownEvent.WaitOne(Timeout.Infinite))
* 因為沒有收到signal, 所以會停在if()這一行, 造成cnt無法累加
*/
Console.WriteLine("{0}", cnt++);
}
}
public void Start()
{
_thread = new Thread(Job);
_thread.Start();
Console.WriteLine("Thread started running");
}
public void Pause()
{
/* Sets the state of the event to nonsignaled,
* causing threads to block.
*/
_pauseEvent.Reset();
Console.WriteLine("Thread paused");
}
public void Resume()
{
/* Sets the state of the event to signaled,
* allowing one or more waiting threads to proceed.
*/
_pauseEvent.Set();
Console.WriteLine("Thread resuming ");
}
public void Stop()
{
// Signal the shutdown event
_shutdownEvent.Set();
Console.WriteLine("Thread Stopped ");
// Make sure to resume any paused threads
_pauseEvent.Set();
// Wait for the thread to exit
_thread.Join();
}
}
來測試Worker
static void Main(string[] args)
{
Worker w1 = new Worker();
w1.Start();
Thread.Sleep(500);
w1.Pause();
Thread.Sleep(200);
w1.Resume();
Thread.Sleep(500);
w1.Pause();
Thread.Sleep(1000);
w1.Resume();
Thread.Sleep(200);
w1.Stop();
Console.Read();
}
Pause()利用 關閉_pauseEvent訊號, 即 _pauseEvent.Reset(),
來達到Job停在_pauseEvent.WaitOne(Timeout.Infinite);這一行程式碼,
這樣操作會比呼叫Thread.Suspend更好
1: public void Pause()
2: {
3: /* Sets the state of the event to nonsignaled,
4: * causing threads to block.
5: */
6: _pauseEvent.Reset();
7: /* 在Job()中_pauseEvent.WaitOne(Timeout.Infinite);
8: * 這一行因為在等signal回覆, 而Reset關閉signal,
9: * 所以間接造成暫停Worker執行緒,
10: * 這個方式會比Thread.Suspend()要好
11: */
12: Console.WriteLine("Thread paused");
13: }
Stop()利用通知_shutdownEvent, 即_shutdownEvent.Set(),
讓Job中
if(_shutdownEvent.WaitOne(0))
break;
條件成立, 跳離while-loop也就順利結束該執行緒
同時為了確保原本執行緒不是被暫停狀態
記得通知_pauseEvent, 即_pauseEvent.Set();
否則通知_shutdownEvent也枉然
最後在很優雅地等執行緒結束,
即 呼叫_thread.Join(); 而不是Thread.Terminate
1: public void Stop()
2: {
3: // Signal the shutdown event
4: _shutdownEvent.Set();
5: Console.WriteLine("Thread Stopped ");
6:
7: // Make sure to resume any paused threads
8: _pauseEvent.Set();
9:
10: // Wait for the thread to exit
11: _thread.Join();
12: }
參考資料:
全站熱搜