多个线程在等待一个事件?

Man*_*nia 5 c# multithreading synchronization

(我认为)我想要的是AutoResetEvent多个线程可以等待的平等,所有都可以在设置时恢复.

我知道这可以通过AutoResetEvent每个线程一个并设置每个线程来实现- 但是有更简单的方法吗?一种不依赖于事件句柄数组的方法?

有效的(我认为)我希望能够做到这一点:

private volatile string state;
private MultiEventHandle stateChanged = new MultiEventHandle();

public void WaitForBlob()
{
  while (true)
  {
    object saved = stateChanged.Current;  // some sentinel value
    if (state == "Blob") break;
    stateChanged.WaitTilNot(saved);  // wait til sentinel value != "current"
  }
}

public void SetBlob()
{
  state = "Blob";
  stateChanged.Change();  // stateChanged.Current becomes a new sentinel object
}
Run Code Online (Sandbox Code Playgroud)

也就是说,任何数量的线程都可以调用WaitForBlob,并且在任何时候(没有竞争条件)SetBlob都可以被另一个线程调用,并且所有等待的线程将立即检测到更改 - 而且重要的是,没有自旋锁或Threading.Sleeps.

现在我想我可以MultiEventHandle相对容易地实现" ".但我的问题是......有更好的方法吗?当然,我认为这是错误的,因为它必须是一个非常常见的用例,但我似乎无法找到一个内置的工具.我担心我可能会在这里发明一个方形轮子.

Man*_*nia 4

我在幕后使用 Monitor.PulseAll/Wait 将可能的解决方案包装到“WatchedVariable”类中(在此过程中了解了一些有关 Monitor 类的信息)。在此发布以防其他人遇到同样的问题 - 可能对不可变数据结构有一定用处。感谢乔恩·斯基特的帮助。

用法:

private WatchedVariable<string> state;

public void WaitForBlob()
{
  string value = state.Value;
  while (value != "Blob")
  {
    value = state.WaitForChange(value);
  }
}
Run Code Online (Sandbox Code Playgroud)

执行:

public class WatchedVariable<T>
    where T : class
{
    private volatile T value;
    private object valueLock = new object();

    public T Value
    {
        get { return value; }
        set
        {
            lock (valueLock)
            {
                this.value = value;
                Monitor.PulseAll(valueLock);  // all waiting threads will resume once we release valueLock
            }
        }
    }

    public T WaitForChange(T fromValue)
    {
        lock (valueLock)
        {
            while (true)
            {
                T nextValue = value;
                if (nextValue != fromValue) return nextValue;  // no race condition here: PulseAll can only be reached once we hit Wait()
                Monitor.Wait(valueLock);  // wait for a changed pulse
            }
        }
    }

    public WatchedVariable(T initValue)
    {
        value = initValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然它通过了我的测试用例,但使用风险自负。

现在咨询元来找出我应该接受哪个答案..