close

今天來複習一下執行緒, 先前有一些觀念錯誤: 關於暫停/關閉執行緒Suspend, Terminate

不該踩到地雷, 我一個都沒錯過@@

1. 本範例示範如何開一個worker執行緒, 呼叫Start開始不斷執行Job內容, 且不影響原本的主執行緒

2. 要暫停一個執行緒不建議使用Thread.Suspend,  這會讓你不曉得在你呼叫Suspend

    當下該執行緒在幹甚麼;更準確地說, 你會不曉得worker在Job中已經

    完成多少(停在Job中的哪個階段)

3. 不要使用Terminate, 建議使用Join

3. 透過ManualResetEvent搭配WaitOne 方法, 可以讓你更精準控制: 暫停, 繼續, 以及停止執行緒

image


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: }

參考資料:

  1. Sample to create, start, pause, resume and terminate a Thread in C#

  2. Is there a way to indefinitely pause a thread?

  3. WaitOne 方法
  4. MethodInvoker Delegate


arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(1) 人氣()