ManualResetEvent
ManualResetEvent有三個重要的方法,分別為:waiteone(),set(),reset(),其含義如下:
1.WaitOne()即等待訊號發出,即可往下執行。
2.set()發出訊號,讓執行緒方法繼續往下執行,並允許其他執行緒(如有)一併往下執行。
3.reset()重新初始化(即:去掉票據)變為ManualResetEvent(false)形式。
官方示例如下:
internal class Program { private static ManualResetEvent mre = new ManualResetEvent(false); static void Main() { Console.WriteLine("\n初始化3個執行緒,並在遇到waitone時阻塞執行:\n"); for (int i = 0; i <= 2; i++) { Thread t = new Thread(ThreadProc); t.Name = "Thread_" + i; t.Start(); } Thread.Sleep(500); Console.WriteLine("\n三個執行緒已經啟動,請按Enter鍵呼叫Set()方法來釋放3個阻塞執行緒"); Console.ReadLine(); mre.Set(); Thread.Sleep(500); Console.WriteLine("\n當這個ManualResetEvent活得訊號,3個執行緒都會從WaitOne()方法內返回,並繼續執行(如果有新執行緒被建立)不會被阻塞,可按Enter鍵進行觀察:\n"); Console.ReadLine(); for (int i = 3; i <= 4; i++) { Thread t = new Thread(ThreadProc); t.Name = "Thread_" + i; t.Start(); } Thread.Sleep(500); Console.WriteLine("\n按Enter鍵呼叫 Reset()方法(設定為無訊號狀態),重新初始化一個執行緒執行,並在WaitOne()方法處停下來\n"); Console.ReadLine(); mre.Reset(); // Start a thread that waits on the ManualResetEvent. Thread t5 = new Thread(ThreadProc); t5.Name = "Thread_5"; t5.Start(); Thread.Sleep(500); Console.WriteLine("\n按Enter鍵呼叫 Set() 方法,然後結束演示."); Console.ReadLine(); mre.Set(); Console.ReadLine(); } private static void ThreadProc() { string name = Thread.CurrentThread.Name; Console.WriteLine(name + " starts and calls mre.WaitOne()"); mre.WaitOne(); Console.WriteLine(name + " ends."); } }
執行結果:
ManualResetEventSlim:
ManualResetEventSlim是ManualResetEvent的簡化版或者叫最佳化版,其主要原理為採用了自旋方式來提高效能,適用於短期內等待的情況,效能比後者要好很多。適用於一次寫入,多次讀取時候的執行緒同步場景。
官方示例程式碼:
internal class Program { static void Main(string[] args) { MRES_SetWaitReset(); Console.ReadKey(); } static void MRES_SetWaitReset() { ManualResetEventSlim mres1 = new ManualResetEventSlim(false); ManualResetEventSlim mres2 = new ManualResetEventSlim(false); ManualResetEventSlim mres3 = new ManualResetEventSlim(true); var observer = Task.Factory.StartNew(() => { mres1.Wait(); Console.WriteLine("mres1!阻塞結束繼續執行"); Console.WriteLine("mres3即將被重置"); mres3.Reset(); Console.WriteLine("mres2即將獲取到票據"); mres2.Set(); }); Console.WriteLine("主執行緒: mres3.IsSet = {0} (should be true)", mres3.IsSet); Console.WriteLine("主執行緒:mres1即將獲取訊號"); mres1.Set(); Console.WriteLine("主執行緒:mres2即將阻塞"); mres2.Wait(); Console.WriteLine("主執行緒:mres2已獲取訊號!"); Console.WriteLine("主執行緒: mres3.IsSet = {0} (should be false)", mres3.IsSet);
observer.Wait(); // make sure that this has fully completed mres1.Dispose(); mres2.Dispose(); mres3.Dispose(); } }
執行結果: