AutoResetEvent.Set() 是做什么的?

What does AutoResetEvent.Set() do ?

如果我这样做:

private static System.Threading.AutoResetEvent event_2 = new System.Threading.AutoResetEvent(false);

然后在主线程中我做:

event_2.Set();

它将状态从 false 更改为 true

如果是这样,基本上是这样:

AutoResetEventState = !AutoResetEventState 

?

A thread waits for a signal by calling WaitOne on the AutoResetEvent. If the AutoResetEvent is in the non-signaled state, the thread blocks, waiting for the thread that currently controls the resource to signal that the resource is available by calling Set.

Calling Set signals AutoResetEvent to release a waiting thread. AutoResetEvent remains signaled until a single waiting thread is released, and then automatically returns to the non-signaled state. If no threads are waiting, the state remains signaled indefinitely.

如果另一个线程正在使用 event_2.Wait() 等待事件并且您从您的线程调用 .Set() ,等待线程将继续执行。

If so , it basically does :

AutoResetEventState = !AutoResetEventState

?

除此之外,它还将 EventWaitHandle 设置为信号状态,允许一个或多个线程继续进行。

它将状态设置为允许线程在 Wait() 上继续执行的状态。

如果有任何线程已经在等待,那么将允许一个线程继续进行并且状态将立即设置为未设置,因此所有其他线程将继续阻塞。

如果当前没有线程在等待,那么将立即允许第一个等待的线程通过,但后续线程将阻塞。

其他 EventWaitHandle 派生的 类 共享相同的通用机制,但允许线程进行时的自动重置与 ManualResetEvent 不同,因此得名。

如果将true传递给构造函数,则初始状态发出信号(允许线程进行),如果传递false则不发出信号,因此传递true是相同的就好像你在构造后立即调用 Set() 而传递 false 相反地就像你调用 Reset().

要添加到其他答案,您需要这个的原因(而不是 bool 属性 您只需切换)是:

  1. 信号:在 e.WaitOne() 阻塞的线程将被 信号,其中之一将继续。如果您想在没有同步原语的情况下自己执行此操作,则必须实现某种轮询; "blocking" 线程必须定期轮询 bool(或者说 int)字段,以检查它是否已更改并允许继续。如果不出意外,这将不必要地消耗 cpu 个周期并且会有延迟(取决于您的轮询间隔)。

  2. 原子性:如果有多个线程在等待,你可以保证只有一个不会被阻塞。使用上述轮询解决方案确保相同的行为将需要使用锁定或原子指令(如 Interlocked class 中的指令)并充分理解可能的编译器和处理器指令 reordering/memory 障碍。

如果您正在寻找一种同步多个线程的简单方法,那么这是 .NET 中最简单(如果不是最简单)的解决方案之一。创建 producer/consumer 队列非常简单:

// Simplified example. Check http://www.albahari.com/threading/part2.aspx
// for detailed explanations of this and other syncronizing constructs

private readonly AutoResetEvent _signal = new AutoResetEvent(false);
private readonly ConcurrentQueue<Something> _queue = new ConcurrentQueue<Something>();

// this method can be called by one or more threads simultaneously
// (although the order of enqueued items cannot be known if many threads are competing)
void ProduceItem(Something s)
{
    _queue.Enqueue(s);  // enqueue item for processing
    _signal.Set();      // signal the consumer thread if it's waiting
}

// this loop should be running on a separate thread.
void ConsumerLoop()
{
    while (!_ending)
    {
        // block until producer signals us
        _signal.WaitOne();

        // process whatever is enqueued 
        Something s = null;
        while (!_ending && _concurrentQueue.TryDequeue(out s))
        {
             Process(s);
        }
    }
}

您需要记住的一件事是,多次连续调用 Set 不一定会多次发出 WaitOne 信号。在此示例中,多个生产者可能会触发 Set 方法,但可能需要几毫秒才能发生上下文切换并且 ConsumerLoop 继续,这意味着只有一个 Set 会有效地获取已处理。