我想(我想)的是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
}
即,任何数量的线程都可以调用
WaitForBlob
,并且在任何时间(无竞争条件),另一个线程都可以调用SetBlob
,所有等待线程将立即检测到更改-重要的是,没有自旋锁或Threading.Sleeps。现在,我认为我可以相对轻松地实现“
MultiEventHandle
”。但是我的问题是...还有更好的方法吗?我肯定会犯错,因为它肯定是一个非常常见的用例,但是我似乎找不到适合该工作的内置工具。恐怕我可能要在这里发明方形车轮。 最佳答案
我在幕后使用Monitor.PulseAll/Wait将可能的解决方案包装到“WatchedVariable”类中(在此过程中了解了一些Monitor类)。万一其他人遇到相同的问题,请在此处发布-对于不可变的数据结构可能有一定用处。感谢乔恩·斯基特(Jon Skeet)的帮助。
用法:
private WatchedVariable<string> state;
public void WaitForBlob()
{
string value = state.Value;
while (value != "Blob")
{
value = state.WaitForChange(value);
}
}
执行:
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;
}
}
尽管通过了我的测试用例,但使用后果自负。
现在咨询meta以确定我应该接受哪个答案。