下面的实现是否是线程安全的?如果不是我错过了什么?我应该在某个地方拥有volatile
个关键字吗?或者在OnProcessingCompleted
方法的某处锁定?如果是这样,在哪里?
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 :(得分:5)
您在获取处理程序时也需要锁定,否则您可能没有最新值:
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler;
lock (completedEventLock)
{
handler = ProcessCompleted;
}
if (handler != null)
handler(this, e);
}
请注意,此不会阻止竞争条件,我们决定执行一组处理程序,然后然后一个处理程序取消订阅。它仍然会被调用,因为我们已经将包含它的多播委托提取到handler
变量中。
除了让处理程序本身意识到它不应再被调用之外,你可以做很多事情。
最好不要尝试使事件成为线程安全的 - 指定订阅只应 更改将引发事件的线程。
答案 1 :(得分:4)
私人ProcessCompleted
成员不需要成为event
- 它可能只是一个字段:private EventHandler<ProcessCompletedEventArgs> ProcessCompleted;
- 在课堂内它总是直接进入字段,所以无论如何,event
的东西都会丢失。
您使用显式锁定对象显示的方法并不比仅具有类似字段的事件(即public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted;
更加 更多线程安全 - 唯一的区别是你没有锁定“这个”(这是一件好事 - 你应该理想避免锁定this
)..“处理程序变量”方法是正确的,但有仍然是side-effects you should be aware of。