5

下面的实现是线程安全的吗?如果不是,我错过了什么?我应该在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);
    }
}

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

4

2 回答 2

6

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

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

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

除了让处理程序本身意识到不应该再调用它之外,您对此无能为力。

可以说最好不要尝试使事件线程安全 - 指定订阅应该在将引发事件的线程中更改。

于 2009-06-24T11:40:13.337 回答
4

ProcessCompleted私有成员不需要是一个event- 它可能只是一个字段:private EventHandler<ProcessCompletedEventArgs> ProcessCompleted;- 在类内部它总是直接进入该字段,所以event无论如何这些东西都会丢失。

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

于 2009-06-24T11:39:51.997 回答