是什么在.NET的ManualResetEvent和的AutoResetEvent之间的区别?(Wh

2019-07-21 12:23发布

我已阅读这个文件,我想我明白了。 一个AutoResetEvent当代码穿过复位event.WaitOne()ManualResetEvent没有。

它是否正确?

Answer 1:

是。 这就像一个收费站和门之间的区别。 的ManualResetEvent是门,其需要手动关闭(重置)。 的AutoResetEvent是一个收费站,允许一辆车去了,并自动关闭之前,下一个能打通。



Answer 2:

试想一下,在AutoResetEvent执行WaitOne()Reset()作为一个原子操作。



Answer 3:

简短的回答是肯定的。 最重要的区别是,一个会的AutoResetEvent只允许一个单一的等待线程继续。 在另一方面,一个ManualResetEvent的将继续允许线程,几个在同一时间就算了,继续下去,直到你告诉它停止(复位)。



Answer 4:

从C#3.0果壳书中抽取,由约瑟夫阿尔巴哈利

线程在C#中-免费电子书

甲ManualResetEvent的是上的AutoResetEvent的变化。 不同之处在于一个线程被允许通过一个电话的WaitOne之后,在没有自动复位,所以像门功能:呼叫设置打开门,允许任意数量的线程是在WaitOne的门通过; 调用复位关闭门,造成潜在地,服务员队列累积,直到它的下一个打开。

人们可以用“旋沉睡”与模拟相结合的布尔“gateOpen”字段(volatile关键字声明的)这个功能 - 反复检查标志,然后睡的时间很短。

ManualResetEvents有时用来发出特定的操作完成,或者线程的完成初始化并准备执行工作。



Answer 5:

我创建简单的例子来阐明理解ManualResetEvent VS AutoResetEvent

AutoResetEvent :让我们假设你有3名工人线程。 如果其中任何线程将调用WaitOne()所有其他2个线程将停止执行,等待信号。 我假设他们使用WaitOne() 它像是; 如果我不工作,没人干活。 在第一个例子中,你可以看到,

autoReset.Set();
Thread.Sleep(1000);
autoReset.Set();

当你调用Set()的所有线程将工作和等待信号。 1秒后,我送第二信号,他们执行和等待( WaitOne() 想想这些人是足球队员,如果一个球员说,我会等到经理打电话给我,和其他人将等到经理告诉他们继续( Set()

public class AutoResetEventSample
{
    private AutoResetEvent autoReset = new AutoResetEvent(false);

    public void RunAll()
    {
        new Thread(Worker1).Start();
        new Thread(Worker2).Start();
        new Thread(Worker3).Start();
        autoReset.Set();
        Thread.Sleep(1000);
        autoReset.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);
            autoReset.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);
            autoReset.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);
            autoReset.WaitOne();
        }
    }
}

在这个例子中,你可以清楚地看到,当你先打Set()它可以让所有的线程去,然后在1秒钟后它标志着所有线程等待! 只要您重新设置,无论他们是在调用WaitOne()内,他们将继续运行,因为你必须手动调用Reset()来阻止他们。

manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.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();
        }
    }
}


Answer 6:

autoResetEvent.WaitOne()

类似于

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

作为一个原子操作



Answer 7:

OK,通常它不是一个好的做法,以增加在同一个线程2分的答案,但我并不想编辑/删除我以前的答案,因为它可以在另一种方式帮助。

现在,我创建,更全面,通俗易懂,运行至中学习下面的控制台应用程序代码段。

只是在两个不同的控制台运行示例,并观察行为。 你会得到更清晰的概念有什么幕后发生的事情。

手动重置事件

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);
        }
    }

}



Answer 8:

是。 这是完全正确的。

你可以看到ManualResetEvent的,以此来表明状态。 什么是(集)或关闭(复位)。 与一些时间的发生。 任何线程等待该州发生的可以继续进行。

一个的AutoResetEvent更媲美的信号。 单稳迹象表明,事情发生。 没有任何时间发生。 通常,但不一定是已经发生的“东西”是小的,需要由一个线程来处理 - 因此单个线程后自动复位消耗了该事件。



Answer 9:

恩,那就对了。

您可以通过这两个的使用得到一个想法。

如果你需要告诉您一些工作和其他(线程)完成等待这个现在可以继续,你应该使用的ManualResetEvent。

如果你需要有任何资源的互斥访问,你应该使用的AutoResetEvent。



Answer 10:

的AutoResetEvent在内存中维护布尔变量。 如果布尔变量为假,则它会阻止线程,如果布尔变量为true,放开线程。

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

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

方法的WaitOne

此方法将阻塞当前线程和等待其他线程的信号。 WaitOne的方法将当前线程进入睡眠线程状态。 如果接收到该信号否则返回假的WaitOne方法返回true。

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");
}

我们通过将2秒作为参数调用了WaitOne方法。 在while循环,它等待2秒钟,然后继续工作的信号。 当线程获得了信号的WaitOne返回true和退出循环并打印“主题得到了信号”。

设置方法

的AutoResetEvent设置方法发送的信号,等待线程继续工作。 下面是调用设置方法的语法。

autoResetEvent.Set();

ManualResetEvent的在内存中维护布尔变量。 当布尔变量是假的,然后它会阻止所有线程,当布尔变量为true,放开所有线程。

当我们实例化一个ManualResetEvent的,我们使用默认的布尔值初始化。

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

在上面的代码中,我们初始化与假值ManualResetEvent的,这意味着所有这些调用的WaitOne方法将阻塞,直到一些线程调用集()方法中的线程。

如果我们真值初始化ManualResetEvent的,所有调用的WaitOne方法线程不会阻止,并自由地继续进行。

WaitOne的方法

此方法将阻塞当前线程和等待其他线程的信号。 如果接收到的信号否则返回false返回true。

下面是调用了WaitOne方法的语法。

manualResetEvent.WaitOne();

在WaitOne的方法的第二过载,我们可以指定该时间间隔,直到当前线程等待该信号。 如果时间内内部,它不接收信号返回false并进入方法的下一行。

下面是在调用方法的WaitOne随时间间隔的语法。

bool isSignalled = manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));

我们有指定为5秒,进入的WaitOne方法。 如果ManualResetEvent的对象不接收5秒的信号,它的isSignalled变量设置为false。

设置方法

这种方法被用于将信号发送到所有等待的线程。 set()方法设置ManualResetEvent的对象布尔变量设置为true。 所有等待的线程畅通,并进一步进行。

下面是调用set()方法的语法。

manualResetEvent.Set();

复位方法

一旦我们调用ManualResetEvent的对象的set()方法,它的布尔仍是如此。 要重置价值,我们可以使用reset()方法。 复位方法改变布尔值设置为false。

下面是调用Reset方法的语法。

manualResetEvent.Reset();

我们必须在调用Set方法,如果我们要多次发送信号给线程后立即调用Reset方法。



Answer 11:

如果你想了解的AutoResetEvent和ManualResetEvent的,你需要了解不穿,但中断!

.NET要联想到低级别的编程中最遥远的可能。

的中断是在低电平编程中使用的一些东西,等于信号从低变高(或反之亦然)。 发生这种情况时该程序中断其正常执行和执行指针移动到处理该事件的功能。

要做的第一件事情时,中断happend是重置其状态,becosa这样的硬件的工作原理:

  1. 销被连接到一个信号和所述硬件侦听它改变(信号只能有两种状态)。
  2. 如果信号变化意味着,发生什么事,硬件投入了内存变量的状态发生了(和它仍然会是这样即使信号变化再次)。
  3. 该方案的通知变量的变化状态和移动执行的处理功能。
  4. 这里的第一件事情做,才能够再次聆听此中断,是该内存变量重置为未发生的状态。

这是ManualResetEvent的和的AutoResetEvent之间的差异。
如果发生ManualResetEvent的,我不复位,它发生下一次我将无法听它。



文章来源: What is the difference between ManualResetEvent and AutoResetEvent in .NET?