AutoResetEvent,继承自EventWaitHandle,用在多线程中保护对共享资源的访问,保证每次只能有一个线程对共享资源进行访问

AutoResetEvent最特别之处,在于每次保证只有一个线程执行逻辑,其他的线程只能等待。

 

AutoResetEvent通过信号量来阻塞和释放线程。其基本原理如下:

1、如果AutoResetEvent在无信号状态时,执行了WaitOne()方法之后,当前线程就会被阻塞,直到该AutoResetEvent在其他地方执行了Set()方法后,此时AutoResetEvent就获得了信号并释放一个线程,然后自动执行Reset()方法(即失去信号)。

如果当AutoResetEvent执行Set()方法后,没有等待任何等待的线程,则该AutoResetEvent会一直保持持有信号;

2、如果AutoResetEvent在有信号时,执行了WaitOne方法,当前线程会被立即释放,并且AutoResetEvent也会失去信号。

代码如下所示:

 

        
static AutoResetEvent autoResetEvent=new AutoResetEvent(true);
static void WorkOnAutoResetEvent(string threadName) { Console.WriteLine($"{threadName} 正在等待中..."); autoResetEvent.WaitOne(); Console.WriteLine($"{threadName} 执行中..."); Thread.Sleep(1000); Console.WriteLine($"{threadName} 执行完毕!"); //得到信号,并释放一个被阻塞的线程,然后丢失信号(即自动执行Reset()方法);如果没有线程可以被释放,则它会一直保持信号 autoResetEvent.Set(); }

 

Main中代码如下所示:

            for (int i = 0; i < 3; i++) {
                string threadName = $"thread_{i}";
                var thread = new Thread(delegate ()
                  {
                      WorkOnAutoResetEvent(threadName);
                  });
                thread.Start();
            }

结果:

 

  

为何AutoResetEvent会被以Auto开始的单词命名,因为它在得到信号并释放一个被阻塞的线程之后,会自动的执行Reset()方法,即自动丢失信号,这就是它的自动之处。

当然,如果它在得到信号,但此时并没有任何阻塞的线程被释放,它就会一直保持持有信号,直到下一个WaitOne()方法被执行。

在调用Set()方法之后,它就获得了信号,如果释放了一个阻塞的线程,它会自动执行Reset()丢失信号;如果没有释放线程,则它不会丢失信号。这是关键之处!

 

参考文献:https://docs.microsoft.com/en-us/dotnet/api/system.threading.autoresetevent?view=netcore-3.1#explicit-interface-implementations

 posted on 2020-10-21 16:59  F风  阅读(162)  评论(0编辑  收藏  举报