我该锁定“事件”吗?

13

在以下情况下,我应该锁定事件吗:

事件 foo;

线程 A:将调用 foo += handler;

线程 B:将调用 foo -= handler;

我应该锁定 foo 吗?


(注:已保留原文中的HTML标签)

1
Jon的回答很好,但在回答之前,我想反问一下,为什么你首先要锁定呢?你认为自己有什么问题,为什么认为锁定可以解决它? 我可以想到许多关于多线程事件的问题;根据你所担心的问题不同,你会使用不同的锁定技术。 - Eric Lippert
1个回答

27

foo 上进行锁定是个不好的主意,因为它的值每次都会改变。你应该在一个不会改变的变量上进行锁定:

private readonly object eventLock = new object();
private EventHandler fooHandler;

public event EventHandler Foo
{
    add
    {
        lock (eventLock)
        {
            fooHandler += value;
        }
    }
    remove
    {
        lock (eventLock)
        {
            fooHandler -= value;
        }
    }
}

private void OnFoo(EventArgs e)
{
    EventHandler handler;
    lock (eventLock)
    {
        handler = fooHandler;
    }
    if (handler != null)
    {
        handler(this, e);
    }
}
注意,如果您使用类似此类的字段式事件:
public event EventHandler Foo;

如果你使用add/remove方法,则会自动在其上加一个"lock(this)"锁,尽管在调用它之前获取处理程序时必须手动添加它(假设您想确保读取最近写入的值)。个人而言,我不喜欢在"this"上加锁,但您可能不介意-这肯定会使代码更简单。


@Jon,我正在直接使用事件调用事件处理程序,像这样foo(),而不是从事件中获取处理程序,我应该添加锁吗? - Benny
2
@Benny:如果您正在使用类似字段的事件,那么您不需要添加/删除以进行锁定。如果您直接调用事件处理程序,您如何防止其为null?请注意,您不能只使用 if(foo!= null){foo(...);},因为 foo 可能在测试后变为null。此外,它也不能保证您会得到最新的值-这就是为什么我在我的 OnFoo 方法中加了锁。(内存模型可能会出现奇怪的事情...) - Jon Skeet
请注意,C# 4中的字段事件代码生成将会发生变化,以解决“lock this”代码异味问题。Chris Burrows将在接下来的几个月内撰写一篇博客详细介绍此事,请关注他的博客获取更多信息。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接