C#:线程安全事件

下面的实现是否是线程安全的? 如果不是我错过了什么? 我应该在某处使用volatile关键字吗? 或OnProcessingCompleted方法中的某个锁? 如果是这样,在哪里?

 public abstract class ProcessBase : IProcess { private readonly object completedEventLock = new object(); private event EventHandler ProcessCompleted; event EventHandler IProcess.ProcessCompleted { add { lock (completedEventLock) ProcessCompleted += value; } remove { lock (completedEventLock) ProcessCompleted -= value; } } protected void OnProcessingCompleted(ProcessCompletedEventArgs e) { EventHandler handler = ProcessCompleted; if (handler != null) handler(this, e); } } 

注意:我有私有事件和显式接口的原因是因为它是一个抽象基类。 从它inheritance的类不应该直接对该事件做任何事情。 添加了类包装器,使其更清晰=)

私有ProcessCompleted成员不需要成为一个event – 它可能只是一个字段: private EventHandler ProcessCompleted; – 在课堂内,它总是直接进入战场,所以无论如何event东西都会丢失。

您使用显式锁定对象显示的方法并不比仅具有类似字段的事件(即public event EventHandler ProcessCompleted; – 唯一的区别是您没有锁定“ “(这是一件好事 – 理想情况下你应该避免锁定this )”处理程序变量“方法是正确的方法,但仍然存在你应该注意的副作用 。

您也需要在获取处理程序时锁定,否则您可能没有最新值:

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

请注意,这不会阻止竞争条件,我们已经决定执行一组处理程序, 然后取消一个处理程序。 它仍然会被调用,因为我们已经将包含它的多播委托提取到handler变量中。

除了让处理程序本身意识到它不应再被调用之外,你可以做很多事情。

最好不要尝试使事件成为线程安全的 – 指定订阅应在引发事件的线程中更改。