2009-12-21 147 views
1

我有一个方法,它调用一个异步方法,并在异步方法完成时触发一个回调。我想创建一个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的被称为()。有没有更好的方法来做到这一点,以避免这个潜在的问题?

+1

在你的代码示例中,我认为你的意思是在'RunSynchronous'的主体内键入'CallAsynchronousMethod'。 – 2009-12-21 21:18:28

+0

@Daniel Yankowsky - 谢谢。你是对的,我做了改变。 – Jeremy 2009-12-21 21:39:40

回答

1

正如Daniel和nobugz所说,使用AutoResetEvent可能会有危险。在异步操作非常短时,您可能会在致电waitRun_m.WaitOne();之前致电 waitRun_m.Set();。我更喜欢这样的事情。这样您就可以确定您将首先进入等待状态,然后调用Pulse方法。另外你不必CloseAutoResetEvent这是经常遗忘。

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); 
} 
+0

错误,我在说AutoResetEvent本身是OK的。正如MSDN的报价所说,Set/WaitOne排序会自行处理。我反对的是,AutoResetEvent是一个字段,每次调用RunSynchronous时都会重新分配该字段,这意味着RunSynchronous本身并不安全,可以被多个线程同时调用。您的解决方案看起来也可以工作,但它不会使RunSynchronous更安全。 – 2009-12-21 22:04:56

3

这不是一个问题,在您完全支持WaitOne之前获取Set的事件。如果情况并非如此,AutoResetEvent将非常不可用。

+0

但是,如果Set被首先调用,那么WaitOne将最终导致线程终止阻塞... – Jeremy 2009-12-21 21:40:49

+0

如果首先调用Set,则一切都会正常。 WaitOne会立即返回。 – 2009-12-21 22:05:37

+0

不是。它是重置它的WaitOne()调用,而不是线程出口。 – 2009-12-21 22:05:39

7

我相信这将会回答你的问题:

呼叫设置信号的AutoResetEvent释放等待线程。 AutoResetEvent保持发送状态,直到释放一个等待线程,然后自动返回到非信号状态。 如果没有线程在等待,状态将无限期地发送。

但是你必须小心,因为现在RunSynchronous不看线程安全。如果两个不同的线程以重叠的方式调用它,那么所有的地狱都可能崩溃。