<div style="background-color:#226DDD;width:100%;padding:10px;auto;text-indent:2em"><font color=#FFFFFF face="Microsoft YaHei" style="font-size:13px"> 本文主要來自一道面試題,因爲以前對AutoResetEvent的概念比較模糊(即便已經使用過了)。面試題題目很簡潔:兩個線程交替打印0~100的奇偶數。你能夠先動手試試,我主要是嘗試在一個方法裏面完成這個任務。 <br/>注: Suspend,Resume來控制線程已經在.net framework2.0被淘汰了,緣由就是掛起以後,但由於異常而沒有及時恢復,若是佔用資源會致使死鎖。 </font></div>html
有了上面的解釋,開始展現代碼(通過屢次優化)面試
//若要將初始狀態設置爲終止,則爲 true;若要將初始狀態設置爲非終止,則爲 false static AutoResetEvent oddResetEvent = new AutoResetEvent(false); static AutoResetEvent evenResetEvent = new AutoResetEvent(false); static int i = 0; static void Main(string[] args) { //ThreadStart是個委託 Thread thread1 = new Thread(new ThreadStart(show)); thread1.Name = "偶數線程"; Thread thread2 = new Thread(new ThreadStart(show)); thread2.Name = "奇數線程"; thread1.Start(); Thread.Sleep(2); //保證偶數線程先運行。 thread2.Start(); Console.Read(); } public static void show() { while (i <= 100) { int num = i % 2; if (num == 0) { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, "evenResetEvent"); if(i!=1) evenResetEvent.Set(); oddResetEvent.WaitOne(); //當前線程阻塞 } else { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, "oddResetEvent"); //若是此時AutoResetEvent 爲非終止狀態,則線程會被阻止,並等待當前控制資源的線程經過調用 Set 來通知資源可用。不然不會被阻止 oddResetEvent.Set(); evenResetEvent.WaitOne(); } } }
結果以下圖所示: 函數
注意點: <font color=red>不要有一點點點點多餘的evenResetEvent.Set(),他會讓後續的 evenResetEvent.WaitOne();失效.</font>性能
此外,咱們利用信號量也能夠實現,信號量是一種內核模式鎖,對性能要求比較高,特殊狀況下才考慮使用,並且要避免在內核模式和用戶模式下頻繁相互切換線程。代碼以下:測試
private static readonly int MaxSize = 1; private static int i = 0; static Semaphore oddSemaphore = new Semaphore(0, MaxSize); static Semaphore evenSemaphore = new Semaphore(0, MaxSize); static void Main(string[] args) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); //ThreadStart是個委託 Thread thread1 = new Thread(new ThreadStart(show)); thread1.Name = "偶數線程"; Thread thread2 = new Thread(new ThreadStart(show)); thread2.Name = "奇數線程"; thread1.Start(); thread2.Start(); thread1.Join(); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); Console.Read(); } private static void show() { if(i==1) evenSemaphore.WaitOne(); while (i <= 100) { int num = i % 2; if (num == 0) { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId); evenSemaphore.Release(); oddSemaphore.WaitOne(); //當前線程阻塞 } else { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId); //釋放一個偶數信號空位出來; oddSemaphore.Release(); evenSemaphore.WaitOne(); //當前線程阻塞 //此時已經消耗了一個奇數信號空位 } } }
這種方法利用線程池自己就是隊列的方式,即先進先出。測試以後發現性能有降低,可是仍是貼出來供參考。優化
static int threadCount = 2; static int count = 0; static object cursorLock = new object(); static void Main(string[] args) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); Task[] arr = new Task[2]; for (int threadIndex = 0; threadIndex < threadCount; threadIndex++) { //這兩種方法均可以 arr[threadIndex] = Task.Factory.StartNew(PrintNum, threadIndex); } Task.WaitAll(arr); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); Console.Read(); } private static void PrintNum(object num) { bool isOk = false; while (!isOk) { lock (cursorLock) { int index = count % 2; if (count>100) { isOk = true; } else if (index == (int)num) { if (index == 0) Console.WriteLine("{0}:{1} {2} ", "偶數線程", Thread.CurrentThread.ManagedThreadId, count++); else Console.WriteLine("{0}:{1} {2} ", "奇數線程", Thread.CurrentThread.ManagedThreadId, count++); } } } }
結果以下: spa
private static int i = 0; static Mutex mutex = new Mutex(); static void Main(string[] args) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); //ThreadStart是個委託 Thread thread1 = new Thread(new ParameterizedThreadStart(show)); thread1.Name = "偶數線程"; Thread thread2 = new Thread(new ParameterizedThreadStart(show)); thread2.Name = "奇數線程"; thread1.Start(0); thread2.Start(1); thread2.Join(); stopwatch.Stop(); Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds); Console.Read(); } /// <summary> /// Mutex的釋放與鎖定 都只能在同一個線程中執行 /// </summary> private static void show(object index) { while (i <= 100) { mutex.WaitOne(); int num = i % 2; if (num == (int)index&&i<=100) { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId); } mutex.ReleaseMutex(); } }
有關概念資料 https://www.cnblogs.com/michaelxu/archive/2008/09/20/1293716.html.net
原文出處:https://www.cnblogs.com/zhan520g/p/11388591.htmlpwa