AutoResetEvent.Set()是做什么的?

12
如果我这样做:
private static System.Threading.AutoResetEvent event_2 = new System.Threading.AutoResetEvent(false);

然后在主线程中我做:

event_2.Set();

它将状态从false更改为true吗?

如果是的话,它基本上做到了:

AutoResetEventState = !AutoResetEventState 

?


1
它向所有等待的线程发送一个信号。 - kevintjuh93
4
不,它仅向一个线程发送信号。请记住这是一个“AutoResetEvent”。 - Sriram Sakthivel
1
Set()事件使树在森林中倒下。如果没有人通过调用WaitOne()来听到它,那么它就不会发出声音。否则,这是一个非常基本的线程同步原语,只有ManualResetEvent更容易理解。 - Hans Passant
5个回答

15

如果线程在 Wait() 上等待,它将把状态设置为允许线程继续执行。

如果已经有线程在等待,则其中一个线程将被允许继续执行,并且状态将立即被设置为未设置,因此所有其他线程都将继续阻塞。

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

其他基于EventWaitHandle的类也使用相同的机制,但是自动重置的方式不同于ManualResetEvent,因此名称也不同。

如果在构造函数中传递true,则初始状态被信号(允许线程继续执行)。如果传递false,则不被信号,因此传递true与在构造后立即调用Set()相同,传递false则与调用Reset()相同。


4
补充其他答案,你需要一个这个(而不是仅仅切换bool属性),原因如下:
1. 信号:处于“e.WaitOne()”阻塞状态的线程将收到“信号”,并且其中一个将继续执行。如果您想要在没有同步机制的情况下自己完成这项工作,就必须实现某种形式的轮询;“阻塞”的线程必须定期轮询bool(或int)字段以检查它是否已更改并且允许继续执行。至少,这会不必要地消耗cpu周期,并且会有延迟(取决于轮询间隔)。
2. 原子性:如果多个线程正在等待,您有保证只有一个线程会被解除阻塞。使用上述轮询解决方案确保相同的行为需要锁定或使用原子指令(例如Interlocked类中找到的指令)以及对可能的编译器和处理器指令重新排序/内存屏障的深刻理解。
如果您正在寻找一种简单的方法来同步多个线程,则这是.NET中最简单(如果不是最简单)的解决方案之一。创建生产者/消费者队列非常简单:
// 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 会被有效处理。


3
一个线程通过在AutoResetEvent上调用WaitOne来等待信号。如果AutoResetEvent处于非信号状态,则线程会阻塞,等待当前控制资源的线程通过调用Set发出可用资源的信号。
调用Set会向AutoResetEvent发送信号以释放等待的线程。AutoResetEvent保持信号状态直到释放单个等待线程,然后自动返回非信号状态。如果没有线程在等待,则状态将无限期地保持为信号状态。
参考链接:https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx

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

那么初始状态是什么?你放一个 truefalse,为了什么? - JAN
这里有很好的解释 - 但是快速的答案是第一个waiter会通过。https://dev59.com/JWYr5IYBdhLWcg3wYZSD - Robert Horvick
如果你想让另一个线程立即运行而不等待,那么初始状态为“true”是有意义的。另一种方法是创建AutoResetEvent,然后立即调用.Set()方法。 - dlxeon

0
如果是这样的话,它基本上会执行以下操作: AutoResetEventState = !AutoResetEventState 对此,它还将设置EventWaitHandle为信号状态,允许一个或多个线程继续进行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接