2009-06-24 118 views
5

線程安全以下的實現?如果不是我錯過了什麼?我應該在哪裏有volatile關鍵字?或在OnProcessingCompleted方法中的某處鎖定?如果是這樣,在哪裏?C#:線程安全事件

public abstract class ProcessBase : IProcess 
{ 
    private readonly object completedEventLock = new object(); 

    private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; 

    event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted 
    { 
     add 
     { 
      lock (completedEventLock) 
       ProcessCompleted += value; 
     } 
     remove 
     { 
      lock (completedEventLock) 
       ProcessCompleted -= value; 
     } 
    } 

    protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
    { 
     EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted; 
     if (handler != null) 
      handler(this, e); 
    } 
} 

注:我之所以有私人事件和顯式接口的東西,是因爲它是一個抽象基類。而從它繼承的類不應該直接對該事件做任何事情。添加類包裝,使其更加清晰=)

+0

(回覆評論) – 2009-06-24 12:48:31

回答

4

沒有必要私營ProcessCompleted成員是一個event - 它可能只是一個字段: - 類裏面總是直接去到外地,所以event的東西無論如何都會丟失。

你已經有明確鎖定對象顯示的方法並不多線程安全不僅僅是一個具有字段般的事件(即public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - 唯一的區別是,你是不是鎖定「本」 (這是一個很好的事情 - 你應該理想避免鎖定在this)。該「處理變量」的做法是正確的,但仍有side-effects you should be aware of

+0

添加了爲什麼我使用私人事件處理程序和顯式事件的東西來我的問題。它仍然不需要?你的意思是這個差別是什麼?公共事件EventHandler SomeEvent會自動鎖定嗎? – Svish 2009-06-24 12:14:20

+2

是;類域事件(即沒有明確添加/刪除的事件)具有內置鎖(this);見語言規範(MS版本)中的10.8.1;然而,這是由類內的代碼繞過 - 請參閱http://marcgravell.blogspot.com/2009/02/fun-with-field-like-events.html;所以作爲* private *事件,添加/刪除(從而鎖定)從不使用。對於明確的接口實現,代碼很好,你需要自己添加鎖,你已經完成了 - 並且可以說比*「lock(this)」更好。堅持下去;-p – 2009-06-24 12:48:00

5

當你獲取處理程序,那麼也需要鎖定否則您可能沒有最新值:

protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
{ 
    EventHandler<ProcessCompletedEventArgs> handler; 
    lock (completedEventLock) 
    { 
     handler = ProcessCompleted; 
    } 
    if (handler != null) 
     handler(this, e); 
} 

請注意,這不會防止競爭條件,我們已決定我們將執行一組處理程序和然後一個處理程序取消訂閱。它仍然會被調用,因爲我們已經將包含它的多播委託取到handler變量中。

除了讓處理程序本身意識到不應該再調用它之外,對此可以做的並不多。

這可以說是最好還是不嘗試使事件線程安全 - 指定訂閱應該在線程的變化,這將引發該事件。