2010-02-05 59 views
13

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

event foo;

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

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

我应该锁foo吗?

+1

乔恩的回答很好,但在回答之前,我会推回去问为什么你首先要做锁定。 *你相信你有什么问题,你为什么认为锁定解决了它?*我可以想到多线程事件可能存在的多个问题;你会根据你担心的问题使用不同的锁定技术。 – 2010-02-05 18:24:54

回答

24

锁定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; 

那么你会自动获得一个“在添加/删除时锁定(this)“,尽管您在调用处理程序之前必须手动添加它(假设您要确保读取最近写入的值)。就我个人而言,我不是锁定“this”的粉丝,但你可能不介意 - 它确实使代码更简单。

+0

@Jon,我正在使用类似场景的事件,所以我不需要锁定添加/删除,我是对吗? – Benny 2010-02-05 08:17:54

+0

@Jon,我直接调用了事件处理函数,像这样foo(),不会从事件中获取处理函数,我应该添加锁吗? – Benny 2010-02-05 08:24:42

+1

@Benny:如果你使用的是类似场景的事件,你不需要*添加/删除来锁定。如果你直接调用事件处理程序,你如何防止它为空?请注意,您不能只使用'if(foo!= null){foo(...); }'as'foo'可以在测试后变成* null。也不能保证你会得到最新的值 - 这就是为什么我在我的'OnFoo'方法中获得锁定的原因。 (内存模型可以做些有趣的事情......) – 2010-02-05 08:26:40