2009-12-21 158 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不看線程安全。如果兩個不同的線程以重疊的方式調用它,那麼所有的地獄都可能崩潰。