浅析C#线程同步事件-WaitHandle
官方:对共享资源的独占访问的操作系统特定的对象
WaitHandle分为:Mutex,Semaphore,EventWaitHandle(分为AutoResetEvent,ManualResetEvent)
一:AutoResetEvent-自动同步事件
class Program { static AutoResetEvent autoResetEvent = new AutoResetEvent(false); //static ManualResetEvent manualResetEvent = new ManualResetEvent(false); static int i = 1;//确保第一个数是奇数 static void Main(string[] args) { //任务:两个线层,分别打奇偶数 Thread thread1 = new Thread(Test); thread1.Name = "奇数线层"; thread1.Start(); Thread.Sleep(1);//确保是奇数先运行 Thread thread2 = new Thread(Test); thread2.Name = "偶数线层"; thread2.Start(); autoResetEvent.Set();//允许等待的线层继续执行 Console.Read(); } static void Test() { while (i<10) { if (i%2!=0)//积数 { autoResetEvent.WaitOne(); Console.WriteLine(Thread.CurrentThread.Name+i++); autoResetEvent.Set(); } else//偶数 { autoResetEvent.WaitOne(); Console.WriteLine(Thread.CurrentThread.Name + i++); autoResetEvent.Set(); } } } }
效果;,如果定义int i为0,由于起始是偶数的关系就需要先让偶数线层运行,原理相同。
其中
autoResetEvent.Set()只允许单一的一个状态改变,独占访问,即多线程时也只触发一次waitone()信号,由于此特性,所以代码每次waitone()后再次Set()就会实现多线层有序触发。
如果没有waitone()后再次Set(),那代码只会执行一次waitone()。即Set后状态默认就为False。
二:ManualResetEvent-手动同步事件
class Program { //static AutoResetEvent autoResetEvent = new AutoResetEvent(false); static ManualResetEvent manualResetEvent = new ManualResetEvent(false); static int i = 1;//确保第一个数是奇数 static void Main(string[] args) { //任务:两个线层,分别打奇偶数 Thread thread1 = new Thread(Test); thread1.Name = "奇数线层"; thread1.Start(); Thread.Sleep(1);//确保是奇数先运行 Thread thread2 = new Thread(Test); thread2.Name = "偶数线层"; thread2.Start(); manualResetEvent.Set();//允许等待的线层继续执行 Console.Read(); } static void Test() { while (i<10) { if (i%2!=0)//积数 { manualResetEvent.WaitOne(); Console.WriteLine(Thread.CurrentThread.Name+i++); //manualResetEvent.Reset(); } else//偶数 { manualResetEvent.WaitOne(); Console.WriteLine(Thread.CurrentThread.Name + i++); //manualResetEvent.Reset(); } } } }
效果:允许多状态改变,同步多线程,即多线程时触发多次waitone()信号,永不停止持续触发,由于此特性,所以代码就会实现多线层无序触发。
想要代码只会执行一次waitone(),就需要调用Reset()。即Manual的Set后状态默认就为true,只有Reset后会将状态默认改为False。
总结:主要是为了线程同步事件,区别就是Auto只开一次就默认主动关一次,需要使用得再次打开;Manual开一次后就默认一直开,需要关时候才调用关。
构造函数时定义true就不需要第一次Set。其中WaitOne函数防止死锁时重载WaitOne(100,false),超时时也会将状态置为False。
三:Semaphore-信号量
private static readonly int MaxSize = 1; private static int i = 0; static Semaphore semaphore = new Semaphore(0, MaxSize); static void Main(string[] args) { Thread thread1 = new Thread(new ThreadStart(show)); thread1.Name = "偶数线程"; Thread thread2 = new Thread(new ThreadStart(show)); thread2.Name = "奇数线程"; thread1.Start(); Thread.Sleep(1); thread2.Start(); Console.Read(); } private static void show() { if (i == 1) semaphore.WaitOne(); while (i <= 10) { int num = i % 2; if (num == 0) { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId); semaphore.Release(); semaphore.WaitOne(); //当前线程阻塞 } else { Console.WriteLine("{0}:{1} {2} ", Thread.CurrentThread.Name, i++, Thread.CurrentThread.ManagedThreadId); semaphore.Release(); semaphore.WaitOne(); //当前线程阻塞 } } }
结果:
其余线程同步问题参考:https://www.cnblogs.com/zhan520g/p/11388591.html
https://www.cnblogs.com/michaelxu/archive/2008/09/20/1293716.html