浅析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

 

posted @ 2021-01-12 17:22  SHW03  阅读(882)  评论(0编辑  收藏  举报