我有一个调用异步方法的方法,以及异步方法完成时触发的回调。
我希望我的方法看起来是同步的,所以我创建了一个AutoResetEvent,称为asyncrhonous方法,在AutoResetEvent实例上调用WaitOne(),我在回调方法中调用Set()。像这样的东西(本例简化):
private System.Threading.AutoResetEvent waitRun_m;
public void RunSynchronous()
{
waitRun_m = new System.Threading.AutoResetEvent(false);
CallAsynchronousMethod();
waitRun_m.WaitOne();
}
private void Callback()
{
waitRun_m.Set();
}
现在,可以在调用WaitOne()之前完成对CallAsynchronousMethod的调用 - 导致在WaitOne()之前调用Set()。有没有更好的方法来避免这个潜在的问题?
答案 0 :(得分:7)
我相信这会回答你的问题:
调用Set信号AutoResetEvent释放等待线程。 AutoResetEvent保持信号状态,直到释放单个等待线程,然后自动返回到非信号状态。 如果没有线程在等待,状态将无限期地发出信号。
但是,您必须小心,因为现在RunSynchronous看起来不是线程安全的。如果两个不同的线程以重叠的方式调用它,那么一切都会破裂。
答案 1 :(得分:3)
这不是问题,在您完全支持WaitOne之前获取Set的事件。如果不是这种情况,AutoResetEvent将无法使用。
答案 2 :(得分:1)
Daniel和nobugz说使用AutoResetEvent
可能很危险。你可能会打电话
当异步操作非常短时,在调用waitRun_m.Set();
之前waitRun_m.WaitOne();
。我更喜欢这样的东西。这样您就可以确定首先进入等待状态,然后调用Pulse
方法。另外,您不必Close
经常被遗忘的AutoResetEvent
。
private readonly object m_lock = new object();
public void RunSynchronous()
{
lock(m_lock) {
CallAsynchronousMethod();
Monitor.Wait(m_lock);
}
}
private void Callback()
{
lock(m_lock)
Monitor.Pulse(m_lock);
}