C# NET中ManualResetEvent和AutoResetEvent的区别是什么?

C# NET中ManualResetEvent和AutoResetEvent的区别是什么?,c#,.net,multithreading,autoresetevent,manualresetevent,C#,.net,Multithreading,Autoresetevent,Manualresetevent,我已经阅读了这方面的文档,我想我理解了。当代码通过event.WaitOne()时,a会重置,但a不会 这是正确的吗?简短的回答是肯定的。最重要的区别是AutoResetEvent只允许一个等待线程继续。另一方面,ManualResetEvent将继续允许多个线程同时执行,直到您告诉它停止(重置它)。是。这就像收费站和门之间的区别。ManualResetEvent是需要手动关闭(复位)的门。AutoResetEvent是一个收费站,允许一辆车通过,并在下一辆车通过之前自动关闭。是。这是绝对正确的

我已经阅读了这方面的文档,我想我理解了。当代码通过
event.WaitOne()
时,a会重置,但a不会


这是正确的吗?

简短的回答是肯定的。最重要的区别是AutoResetEvent只允许一个等待线程继续。另一方面,ManualResetEvent将继续允许多个线程同时执行,直到您告诉它停止(重置它)。

是。这就像收费站和门之间的区别。
ManualResetEvent
是需要手动关闭(复位)的门。
AutoResetEvent
是一个收费站,允许一辆车通过,并在下一辆车通过之前自动关闭。

是。这是绝对正确的

您可以将ManualResetEvent视为指示状态的一种方式。有些东西是开的(设置)或关的(重置)。有一定持续时间的事件。任何等待该状态发生的线程都可以继续


自动还原事件更类似于信号。某件事发生的一次性迹象。没有持续时间的事件。通常(但不一定)发生的“某事”很小,需要由单个线程处理——因此,在单个线程消耗事件后自动重置

想象一下,
AutoResetEvent
作为单个原子操作执行
WaitOne()
Reset()

摘自C#3.0简而言之,作者 约瑟夫·阿尔巴哈里

ManualResetEvent是AutoResetEvent的一种变体。它的不同之处在于,它不会在WaitOne调用中让线程通过后自动重置,因此其功能类似于gate:调用集打开gate,允许任何数量的线程在gate处等待一个线程通过;调用Reset会关闭闸门,可能会导致排队等候者累积,直到下一个闸门打开

你可以用一个布尔“gateOpen”字段(用volatile关键字声明)和“spin sleep”来模拟这个功能——反复检查标志,然后在短时间内睡眠

ManualResetEvents有时用于表示特定操作已完成,或线程已完成初始化并准备好执行工作。

是的,没错

你可以通过使用这两个来了解情况

如果您需要告知您已完成某些工作,而其他(线程)正在等待此操作,则应使用ManualResetEvent


如果您需要对任何资源进行互斥访问,您应该使用AutoResetEvent。

我创建了一些简单的示例,以澄清对
ManualResetEvent
vs
AutoResetEvent
的理解

AutoResetEvent
:假设您有3个工作线程。如果这些线程中的任何一个将调用
WaitOne()
所有其他两个线程将停止执行并等待信号。我假设他们正在使用
WaitOne()
。它就像;如果我不工作,就没有人工作。在第一个示例中,您可以看到

autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();
当您调用
Set()
时,所有线程都将工作并等待信号。1秒后,我发送第二个信号,它们执行并等待(
WaitOne()
)。想想这些人都是足球队员,如果一个球员说我会等到经理打电话给我,其他人会等到经理告诉他们继续(
Set()

这更多的是关于裁判员/球员之间的关系,无论任何球员受伤,等待比赛的其他球员将继续工作。如果裁判说等待(
Reset()
),那么所有球员将等待下一个信号

public class ManualResetEventSample
{
    private ManualResetEvent manualReset = new ManualResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        manualReset.Set();
        Thread.Sleep(1000);
        manualReset.Reset();
        Console.WriteLine("Press to release all threads.");
        Console.ReadLine();
        manualReset.Set();
        Console.WriteLine("Main thread reached to end.");
    }

    public void Worker1()
    {
        Console.WriteLine("Entered in worker 1");
        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker1 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker2()
    {
        Console.WriteLine("Entered in worker 2");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker2 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
    public void Worker3()
    {
        Console.WriteLine("Entered in worker 3");

        for (int i = 0; i < 5; i++) {
            Console.WriteLine("Worker3 is running {0}", i);
            Thread.Sleep(2000);
            manualReset.WaitOne();
        }
    }
}
公共类手册重置事件示例
{
私人手动复位事件手动复位=新手动复位事件(假);
public void RunAll()
{
新线程(Worker1.Start();
新线程(Worker2.Start();
新线程(Worker3.Start();
手动复位。设置();
睡眠(1000);
手动复位。复位();
控制台。WriteLine(“按下以释放所有线程”);
Console.ReadLine();
手动复位。设置();
WriteLine(“主线程已到达末尾”);
}
公开作废工作1()
{
Console.WriteLine(“在worker 1中输入”);
对于(int i=0;i<5;i++){
WriteLine(“Worker1正在运行{0}”,i);
《睡眠》(2000年);
manualReset.WaitOne();
}
}
公共空工2()
{
Console.WriteLine(“在worker 2中输入”);
对于(int i=0;i<5;i++){
WriteLine(“Worker2正在运行{0}”,i);
《睡眠》(2000年);
manualReset.WaitOne();
}
}
公开作废工作3()
{
Console.WriteLine(“在worker 3中输入”);
对于(int i=0;i<5;i++){
WriteLine(“Worker3正在运行{0}”,i);
《睡眠》(2000年);
manualReset.WaitOne();
}
}
}

autoResetEvent.WaitOne()

类似于

try
{
   manualResetEvent.WaitOne();
}
finally
{
   manualResetEvent.Reset();
}

作为一种原子操作,AutoResetEvent在内存中维护一个布尔变量。如果布尔变量为false,则会阻止线程;如果布尔变量为true,则会取消阻止线程

当实例化AutoResetEvent对象时,我们在构造函数中传递布尔值的默认值。下面是实例化AutoResetEvent对象的语法

AutoResetEvent autoResetEvent = new AutoResetEvent(false);
WaitOne方法

此方法阻塞当前线程并等待其他线程发出的信号。WaitOne方法将当前线程置于睡眠线程状态。如果WaitOne方法接收到信号,则返回true,否则返回false

autoResetEvent.WaitOne();
WaitOne方法的第二次重载将等待指定的秒数。如果它没有得到任何信号,线程将继续其工作

static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }

    Console.WriteLine("Thread got signal");
}
我们叫
autoResetEvent.WaitOne();
static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }

    Console.WriteLine("Thread got signal");
}
autoResetEvent.Set();
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
manualResetEvent.WaitOne();
bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
manualResetEvent.Set();
manualResetEvent.Reset();
using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class ManualResetEventSample
    {
        private readonly ManualResetEvent _manualReset = new ManualResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call ManualResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call ManualResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _manualReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("It ran one more time. Why? Even Reset Sets the state of the event to nonsignaled (false), causing threads to block, this will initial the state, and threads will run again until they WaitOne().");
            Thread.Sleep(10000);
            Console.WriteLine();
            Console.WriteLine("This will go so on. Everytime you call Set(), ManualResetEvent will let ALL threads to run. So if you want synchronization between them, consider using AutoReset event, or simply user TPL (Task Parallel Library).");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker1 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker2 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Worker3 is running {0}/10. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                // this gets blocked until _autoReset gets signal
                _manualReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}
using System;
using System.Threading;

namespace ConsoleApplicationDotNetBasics.ThreadingExamples
{
    public class AutoResetEventSample
    {
        private readonly AutoResetEvent _autoReset = new AutoResetEvent(false);

        public void RunAll()
        {
            new Thread(Worker1).Start();
            new Thread(Worker2).Start();
            new Thread(Worker3).Start();
            Console.WriteLine("All Threads Scheduled to RUN!. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Main Thread is waiting for 15 seconds, observe 3 thread behaviour. All threads run once and stopped. Why? Because they call WaitOne() internally. They will wait until signals arrive, down below.");
            Thread.Sleep(15000);
            Console.WriteLine("1- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("2- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("3- Main will call AutoResetEvent.Set() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Set();
            Thread.Sleep(2000);
            Console.WriteLine("4- Main will call AutoResetEvent.Reset() in 5 seconds, watch out!");
            Thread.Sleep(5000);
            _autoReset.Reset();
            Thread.Sleep(2000);
            Console.WriteLine("Nothing happened. Why? Becasuse Reset Sets the state of the event to nonsignaled, causing threads to block. Since they are already blocked, it will not affect anything.");
            Thread.Sleep(10000);
            Console.WriteLine("This will go so on. Everytime you call Set(), AutoResetEvent will let another thread to run. It will make it automatically, so you do not need to worry about thread running order, unless you want it manually!");
            Thread.Sleep(5000);
            Console.WriteLine("Main thread reached to end! ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);

        }

        public void Worker1()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker1 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker1 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker2()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker2 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker2 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
        public void Worker3()
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("Worker3 is running {0}/5. ThreadId: {1}.", i, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(500);
                // this gets blocked until _autoReset gets signal
                _autoReset.WaitOne();
            }
            Console.WriteLine("Worker3 is DONE. ThreadId: {0}", Thread.CurrentThread.ManagedThreadId);
        }
    }

}