<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