.NET 中的 ManualResetEvent 和 AutoResetEvent 有什么区别?

发布于 2024-07-06 06:18:43 字数 370 浏览 15 评论 0原文

我已经阅读了这方面的文档,我想我明白了。 当 AutoResetEvent 重置时代码通过 event.WaitOne(),但是 ManualResetEvent 没有。

它是否正确?

I have read the documentation on this and I think I understand. An AutoResetEvent resets when the code passes through event.WaitOne(), but a ManualResetEvent does not.

Is this correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

三五鸿雁 2024-07-13 06:18:44

恩,那就对了。

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

如果您需要告诉您已完成一些工作并且等待此操作的其他(线程)现在可以继续,您应该使用 ManualResetEvent。

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

Yes, thats right.

You can get an idea by the usage of these two.

If you need to tell that you are finished with some work and other (threads) waiting for this can now proceed, you should use ManualResetEvent.

If you need to have mutual exclusive access to any resource, you should use AutoResetEvent.

寂寞陪衬 2024-07-13 06:18:44

如果您想了解 AutoResetEvent 和 ManualResetEvent,您需要了解的不是线程而是中断!

.NET 希望尽可能地实现低级编程。

中断是低级编程中使用的东西,相当于从低电平变为高电平的信号(反之亦然)。 当这种情况发生时,程序会中断其正常执行,并将执行指针移动到处理该事件的函数。

当中断发生时要做的第一件事是重置其状态,因为硬件以这种方式工作:

  1. 一个引脚连接到一个信号,硬件监听它的变化(信号可能有只有两个状态)。
  2. 如果信号发生变化意味着发生了某些事情,并且硬件将内存变量放入发生的状态(即使信号再次发生变化,它仍然如此)。
  3. 程序注意到变量改变状态并将执行转移到处理函数。
  4. 这里要做的第一件事,为了能够再次监听这个中断,就是重置这个内存变量到未发生的状态。

这就是ManualResetEvent和AutoResetEvent之间的区别。
如果 ManualResetEvent 发生并且我没有重置它,那么下次发生时我将无法监听它。

If you want to understand AutoResetEvent and ManualResetEvent you need to understand not threading but interrupts!

.NET wants to conjure up low-level programming the most distant possible.

An interrupts is something used in low-level programming which equals to a signal that from low became high (or viceversa). When this happens the program interrupt its normal execution and move the execution pointer to the function that handles this event.

The first thing to do when an interrupt happend is to reset its state, becosa the hardware works in this way:

  1. a pin is connected to a signal and the hardware listen for it to change (the signal could have only two states).
  2. if the signal changes means that something happened and the hardware put a memory variable to the state happened (and it remain like this even if the signal change again).
  3. the program notice that variable change states and move the execution to a handling function.
  4. here the first thing to do, to be able to listen again this interrupt, is to reset this memory variable to the state not-happened.

This is the difference between ManualResetEvent and AutoResetEvent.
If a ManualResetEvent happen and I do not reset it, the next time it happens I will not be able to listen it.

深府石板幽径 2024-07-13 06:18:43

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

Yes. It's like the difference between a tollbooth and a door. The ManualResetEvent is the door, which needs to be closed (reset) manually. The AutoResetEvent is a tollbooth, allowing one car to go by and automatically closing before the next one can get through.

我一直都在从未离去 2024-07-13 06:18:43

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

AutoResetEvent 还保证只释放一个等待线程。

Just imagine that the AutoResetEvent executes WaitOne() and Reset() as a single atomic operation.

The AutoResetEvent also guarantees to only release one waiting thread.

筱武穆 2024-07-13 06:18:43

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

The short answer is yes. The most important difference is that an AutoResetEvent will only allow one single waiting thread to continue. A ManualResetEvent on the other hand will keep allowing threads, several at the same time even, to continue until you tell it to stop (Reset it).

怀里藏娇 2024-07-13 06:18:43

摘自《C# 3.0 Nutshell》一书,作者:
约瑟夫·阿尔巴哈里

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

ManualResetEvent 是 AutoResetEvent 的变体。 它的不同之处在于,在 WaitOne 调用允许线程通过后,它不会自动重置,因此其功能就像一个门:调用 Set 打开门,允许任意数量的 WaitOne 在门上的线程通过; 调用 Reset 会关闭门,可能会导致等待队列不断累积,直到下一次打开为止。

人们可以使用布尔值“gateOpen”字段(用 volatile 关键字声明)结合“spin-sleeping”来模拟此功能 ​​- 重复检查标志,然后休眠一小段时间。

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

Taken from C# 3.0 Nutshell book, by
Joseph Albahari

Threading in C# - Free E-Book

A ManualResetEvent is a variation on AutoResetEvent. It differs in that it doesn't automatically reset after a thread is let through on a WaitOne call, and so functions like a gate: calling Set opens the gate, allowing any number of threads that WaitOne at the gate through; calling Reset closes the gate, causing, potentially, a queue of waiters to accumulate until its next opened.

One could simulate this functionality with a boolean "gateOpen" field (declared with the volatile keyword) in combination with "spin-sleeping" – repeatedly checking the flag, and then sleeping for a short period of time.

ManualResetEvents are sometimes used to signal that a particular operation is complete, or that a thread's completed initialization and is ready to perform work.

瀞厅☆埖开 2024-07-13 06:18:43

我创建了简单的示例来阐明对 ManualResetEventAutoResetEvent 的理解。

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

I created simple examples to clarify understanding of ManualResetEvent vs AutoResetEvent.

AutoResetEvent: lets assume you have 3 workers thread. If any of those threads will call WaitOne() all other 2 threads will stop execution and wait for signal. I am assuming they are using WaitOne(). It is like; if I do not work, nobody works. In first example you can see that

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

When you call Set() all threads will work and wait for signal. After 1 second I am sending second signal and they execute and wait (WaitOne()). Think about these guys are soccer team players and if one player says I will wait until manager calls me, and others will wait until manager tells them to continue (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();
        }
    }
}

In this example you can clearly see that when you first hit Set() it will let all threads go, then after 1 second it signals all threads to wait! As soon as you set them again regardless they are calling WaitOne() inside, they will keep running because you have to manually call Reset() to stop them all.

manualReset.Set();
Thread.Sleep(1000);
manualReset.Reset();
Console.WriteLine("Press to release all threads.");
Console.ReadLine();
manualReset.Set();

It is more about Referee/Players relationship there regardless of any of the player is injured and wait for playing others will continue to work. If Referee says wait (Reset()) then all players will wait until next signal.

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();
        }
    }
}
罗罗贝儿 2024-07-13 06:18:43

autoResetEvent.WaitOne()

类似于

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

原子操作

autoResetEvent.WaitOne()

is similar to

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

as an atomic operation

ˉ厌 2024-07-13 06:18:43

好吧,通常在同一个线程中添加 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);
        }
    }

}

自动重置事件输出

OK, normally it does not a good practice to add 2 answers in same thread, but I did not want to edit/delete my previous answer, since it can help on another manner.

Now, I created, much more comprehensive, and easy to understand, run-to-learn console app snippet below.

Just run the examples on two different consoles, and observe behaviour. You will get much more clear idea there what is happening behind the scenes.

Manual Reset Event

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

}

Manual Reset Event Output

Auto Reset Event

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

}

Auto Reset Event Output

度的依靠╰つ 2024-07-13 06:18:43

AutoResetEvent 在内存中维护一个布尔变量。 如果布尔变量为 false,则它会阻塞线程;如果布尔变量为 true,则它将解锁线程。

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

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

WaitOne方法

该方法阻塞当前线程并等待其他线程的信号。 WaitOne方法使当前线程进入Sleep线程状态。 如果 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");
}

我们通过传递 2 秒作为参数来调用 WaitOne 方法。 在 while 循环中,它等待信号 2 秒,然后继续工作。 当线程收到信号时,WaitOne 返回 true 并退出循环并打印“线程收到信号”。

Set 方法

AutoResetEvent Set 方法向等待线程发送信号以继续其工作。 以下是调用 Set 方法的语法。

autoResetEvent.Set();

ManualResetEvent 在内存中维护一个布尔变量。 当布尔变量为 false 时,它​​会阻止所有线程,而当布尔变量为 true 时,它​​会取消阻止所有线程。

当我们实例化 ManualResetEvent 时,我们使用默认布尔值对其进行初始化。

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

在上面的代码中,我们用 false 值初始化 ManualResetEvent,这意味着所有调用 WaitOne 方法的线程都将阻塞,直到某个线程调用 Set() 方法。

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

WaitOne 方法

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

以下是调用 WaitOne 方法的语法。

manualResetEvent.WaitOne();

在WaitOne方法的第二次重载中,我们可以指定当前线程等待信号的时间间隔。 如果在内部时间内,它没有收到信号,则返回 false 并进入下一行方法。

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

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

我们在 WaitOne 方法中指定了 5 秒。 如果 ManualResetEvent 对象在 5 秒内未收到信号,则会将 isSignalled 变量设置为 false。

Set 方法

该方法用于向所有等待线程发送信号。 Set() 方法将 ManualResetEvent 对象布尔变量设置为 true。 所有等待的线程都被解除阻塞并继续进行。

以下是调用 Set() 方法的语法。

manualResetEvent.Set();

重置方法

一旦我们调用 ManualResetEvent 对象的 Set() 方法,它的布尔值仍然为 true。 要重置该值,我们可以使用 Reset() 方法。 Reset 方法将布尔值更改为 false。

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

manualResetEvent.Reset();

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

AutoResetEvent maintains a boolean variable in memory. If the boolean variable is false then it blocks the thread and if the boolean variable is true it unblocks the thread.

When we instantiate an AutoResetEvent object, we pass the default value of boolean value in the constructor. Below is the syntax of instantiate an AutoResetEvent object.

AutoResetEvent autoResetEvent = new AutoResetEvent(false);

WaitOne method

This method blocks the current thread and wait for the signal by other thread. WaitOne method puts the current thread into a Sleep thread state. WaitOne method returns true if it receives the signal else returns false.

autoResetEvent.WaitOne();

Second overload of WaitOne method wait for the specified number of seconds. If it does not get any signal thread continues its work.

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

    Console.WriteLine("Thread got signal");
}

We called WaitOne method by passing the 2 seconds as arguments. In the while loop, it wait for the signal for 2 seconds then it continues its work. When the thread got the signal WaitOne returns true and exits the loop and print the "Thread got signal".

Set method

AutoResetEvent Set method sent the signal to the waiting thread to proceed its work. Below is the syntax of calling Set method.

autoResetEvent.Set();

ManualResetEvent maintains a boolean variable in memory. When the boolean variable is false then it blocks all threads and when the boolean variable is true it unblocks all threads.

When we instantiate a ManualResetEvent, we initialize it with default boolean value.

ManualResetEvent manualResetEvent = new ManualResetEvent(false);

In the above code, we initialize the ManualResetEvent with false value, that means all the threads which calls the WaitOne method will block until some thread calls the Set() method.

If we initialize ManualResetEvent with true value, all the threads which calls the WaitOne method will not block and free to proceed further.

WaitOne Method

This method blocks the current thread and wait for the signal by other thread. It returns true if its receives a signal else returns false.

Below is the syntax of calling WaitOne method.

manualResetEvent.WaitOne();

In the second overload of WaitOne method, we can specify the time interval till the current thread wait for the signal. If within time internal, it does not receives a signal it returns false and goes into the next line of method.

Below is the syntax of calling WaitOne method with time interval.

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

We have specify 5 seconds into the WaitOne method. If the manualResetEvent object does not receives a signal between 5 seconds, it set the isSignalled variable to false.

Set Method

This method is used for sending the signal to all waiting threads. Set() Method set the ManualResetEvent object boolean variable to true. All the waiting threads are unblocked and proceed further.

Below is the syntax of calling Set() method.

manualResetEvent.Set();

Reset Method

Once we call the Set() method on the ManualResetEvent object, its boolean remains true. To reset the value we can use Reset() method. Reset method change the boolean value to false.

Below is the syntax of calling Reset method.

manualResetEvent.Reset();

We must immediately call Reset method after calling Set method if we want to send signal to threads multiple times.

那伤。 2024-07-13 06:18:43

是的。 这是绝对正确的。

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

AutoResetEvent 更类似于信号。 一枪表明发生了什么事。 没有任何持续时间的事件。 通常但不一定,发生的“事情”很小,需要由单个线程处理 - 因此在单个线程消耗事件后自动重置。

Yes. This is absolutely correct.

You could see ManualResetEvent as a way to indicate state. Something is on (Set) or off (Reset). An occurrence with some duration. Any thread waiting for that state to happen can proceed.

An AutoResetEvent is more comparable to a signal. A one shot indication that something has happened. An occurrence without any duration. Typically but not necessarily the "something" that has happened is small and needs to be handled by a single thread - hence the automatic reset after a single thread have consumed the event.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文