2013-05-07 103 views
2

我不知道是否是這個觸發在C#中的事件的方式:如何安全地觸發事件?

public event EventHandler<ActionEventArgs> ActionDataReceived; 

public void showLog(string logMessage) 
{ 
    ActionDataReceived(this, new ActionEventArgs(logMessage)); 
} 

回答

5

的安全的方式是採取處理程序的副本,並提高該替代即

var handler = ActionDataReceived; 
if (handler != null) 
{ 
    handler(this, new ActionEventArgs(logMessage)); 
} 

這將在嘗試提升之前減輕可能導致事件未被分配的競爭條件。


由於@EricLippert指出這覆蓋在處理器的內部狀態改變發生後轉讓的情形。

+1

我向你保證,它不會減輕任何**競爭條件;它只會減輕競爭條件,因此在檢查無效後將事件更改爲空。例如,假設我們在線程Alpha和Bravo之間有以下種族:Alpha將委託複製到處理程序並檢查它是否爲空。然後Bravo從事件處理程序列表中刪除方法M,並*銷燬M需要正確操作的狀態*假設不正確,那麼M永遠不會再被調用,因爲它不再是處理程序。然後Alpha調用M,這會爆炸。 – 2013-05-07 17:15:36

+0

這種模式根本不能緩解那場比賽;如果那是你所處的狀況,那麼你必須找到一些其他方式來緩解比賽。一般來說,最好的辦法是:如果你這樣做會傷害你,不要這樣做。多線程程序中的處理程序應該總是處於可安全調用的狀態,而不管它是否當前註冊爲處理程序或不處理。 – 2013-05-07 17:16:54

+0

@EricLippert由*任何*競爭條件我指的是事件可能未被分配/更改的任何情況。但是,從你所說的處理程序仍然可以改變?這是我的理解,一旦你拿了一個處理程序的副本,它會按原樣執行(不管它在調用之前是否隨後被更改)。 – James 2013-05-08 08:16:33