如何阻止异步呼叫完成?
我有一个方法,它调用一个异步方法,并在异步方法完成时触发一个回调。我想创建一个AutoResetEvent,称为异步方法,在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();
}
现在,是有可能调用CallAsynchronousMethod到了WaitOne之前完成()被调用 - 导致set()来之前WaitOne的被称为()。有没有更好的方法来做到这一点,以避免这个潜在的问题?
正如Daniel和nobugz所说,使用AutoResetEvent
可能会有危险。在异步操作非常短时,您可能会在致电waitRun_m.WaitOne();
之前致电 waitRun_m.Set();
。我更喜欢这样的事情。这样您就可以确定您将首先进入等待状态,然后调用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);
}
错误,我在说AutoResetEvent本身是OK的。正如MSDN的报价所说,Set/WaitOne排序会自行处理。我反对的是,AutoResetEvent是一个字段,每次调用RunSynchronous时都会重新分配该字段,这意味着RunSynchronous本身并不安全,可以被多个线程同时调用。您的解决方案看起来也可以工作,但它不会使RunSynchronous更安全。 – 2009-12-21 22:04:56
这不是一个问题,在您完全支持WaitOne之前获取Set的事件。如果情况并非如此,AutoResetEvent将非常不可用。
但是,如果Set被首先调用,那么WaitOne将最终导致线程终止阻塞... – Jeremy 2009-12-21 21:40:49
如果首先调用Set,则一切都会正常。 WaitOne会立即返回。 – 2009-12-21 22:05:37
不是。它是重置它的WaitOne()调用,而不是线程出口。 – 2009-12-21 22:05:39
我相信这将会回答你的问题:
呼叫设置信号的AutoResetEvent释放等待线程。 AutoResetEvent保持发送状态,直到释放一个等待线程,然后自动返回到非信号状态。 如果没有线程在等待,状态将无限期地发送。
但是你必须小心,因为现在RunSynchronous不看线程安全。如果两个不同的线程以重叠的方式调用它,那么所有的地狱都可能崩溃。
在你的代码示例中,我认为你的意思是在'RunSynchronous'的主体内键入'CallAsynchronousMethod'。 – 2009-12-21 21:18:28
@Daniel Yankowsky - 谢谢。你是对的,我做了改变。 – Jeremy 2009-12-21 21:39:40