2009-06-24 120 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变量中。

除了让处理程序本身意识到不应该再调用它之外,对此可以做的并不多。

这可以说是最好还是不尝试使事件线程安全 - 指定订阅应该在线程的变化,这将引发该事件。