From: 011netservice@gmail.com Date: 2022-04-24 Subject: ManualResetEvent.txt ManualResetEvent 摘要: // Sample: // ManualResetEvent DoneEvent = new ManualResetEvent(false); // 主執行緒宣告 // DoneEvent.WaitOne(new TimeSpan(0, 0, 0, 0, 500)); // 主執行緒等待 0.5 秒 // DoneEvent.Set(); // 子執行緒發出訊號通知主執行緒繼續執行. 1. ManualResetEvent 表示一個狀態: Signaled 或 Nonsignaled. 2. ManuelResetEvent的狀態, 可在建立物件的時候, 設定初始值為Signaled 或 Nonsignaled. 3. 若要切換ManuelResetEvent的狀態, 則以Set()設定為Signaled, 或以Reset()設定為Nonsignaled. 4. 若在 Nonsignaled 狀態時, 則 WaitOne() 會封鎖目前的執行緒, 直到收到 Signaled, 才會繼續執行目前的執行緒. 5. WaitOne可指定封鎖時間, 若 (超過封鎖時間 或 Signaled), 才會繼續執行目前的執行緒, 否則會封鎖目前的執行緒. ---------- 20200714 https://stackoverflow.com/questions/6529659/wait-for-queueuserworkitem-to-complete You could use events to sync. Like this: private static ManualResetEvent resetEvent = new ManualResetEvent(false); public static void Main() { ThreadPool.QueueUserWorkItem(arg => DoWork()); resetEvent.WaitOne(); } public static void DoWork() { Thread.Sleep(5000); resetEvent.Set(); } If you don't want to embed event set into your method, you could do something like this: var resetEvent = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem( arg => { DoWork(); resetEvent.Set(); }); resetEvent.WaitOne(); For multiple items: var events = new List(); foreach(var job in jobs) { var resetEvent = new ManualResetEvent(false); ThreadPool.QueueUserWorkItem( arg => { DoWork(job); resetEvent.Set(); }); events.Add(resetEvent); } WaitHandle.WaitAll(events.ToArray()); ----------- 20181119 ref: http://me1237guy.pixnet.net/blog/post/61422592-c%23-如何創建%2C-暫停%2C-繼續%2C-終止一個執行緒%28threa C# 如何創建, 暫停, 繼續, 終止一個執行緒(Thread) 今天來複習一下執行緒, 先前有一些觀念錯誤: 關於暫停/關閉執行緒Suspend, Terminate 不該踩到地雷, 我一個都沒錯過@@ 1. 本範例示範如何開一個worker執行緒, 呼叫Start開始不斷執行Job內容, 且不影響原本的主執行緒 2. 要暫停一個執行緒不建議使用Thread.Suspend, 這會讓你不曉得在你呼叫Suspend 當下該執行緒在幹甚麼;更準確地說, 你會不曉得worker在Job中已經 完成多少(停在Job中的哪個階段) 3. 不要使用Terminate, 建議使用Join 4. 透過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(); } } 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更好 public void Pause() { /* Sets the state of the event to nonsignaled, * causing threads to block. */ _pauseEvent.Reset(); /* 在Job()中_pauseEvent.WaitOne(Timeout.Infinite); * 這一行因為在等signal回覆, 而Reset關閉signal, * 所以間接造成暫停Worker執行緒, * 這個方式會比Thread.Suspend()要好 */ Console.WriteLine("Thread paused"); } Stop()利用通知_shutdownEvent, 即_shutdownEvent.Set(), 讓Job中 if(_shutdownEvent.WaitOne(0)) break; 條件成立, 跳離while-loop也就順利結束該執行緒 同時為了確保原本執行緒不是被暫停狀態 記得通知_pauseEvent, 即_pauseEvent.Set(); 否則通知_shutdownEvent也枉然 最後在很優雅地等執行緒結束, 即 呼叫_thread.Join(); 而不是Thread.Terminate 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(); }