注册 C# 事件是否线程安全
本文关键字:线程 安全 是否 事件 注册 | 更新日期: 2023-09-27 17:56:12
具体来说,"+="操作是原子的吗?如果我使用"event"关键字,或者只是一个普通的旧委托,这有什么区别吗?
对于大多数类型,它是读取,然后是"+"运算符,然后是写入。 所以,它不是原子的。 我想知道代表/活动是否有特殊情况。
这种代码是必要的还是多余的:
Action handler;
object lockObj;
public event Action Handler {
add { lock(lockObj) { handler += value; } }
remove { lock(lockObj) { handler -= value; } }
}
是的,自动实现的事件上的+=
和-=
运算符是原子的(如果库使用自定义事件处理程序,则很容易不是原子的)。摘自 MSDN 杂志文章 .NET Matters: Event Accessors
当 C# 编译器为 MyClass 生成代码时,输出 ® Microsoft中间语言 (MSIL) 在行为上与 使用如图 1 所示的代码生成的内容。
图 1 扩展事件实现
class MyClass { private EventHandler _myEvent; public event EventHandler MyEvent { [MethodImpl(MethodImplOptions.Synchronized)] add { _myEvent = (EventHandler)Delegate.Combine(_myEvent, value); } [MethodImpl(MethodImplOptions.Synchronized)] remove { _myEvent = (EventHandler)Delegate.Remove(_myEvent, value); } } ... }
[...]
显式事件实现的另一个用途是提供自定义 同步机制(或删除一个)。您会在图中注意到 1 添加和删除访问器都装饰有 指定访问器应为 同步。对于实例事件,此属性等效于 使用当前锁包装每个访问器的内容 实例:
add { lock(this) _myEvent += value; } remove { lock(this) _myEvent -= value; }
如此处所述,add
处理程序以线程安全的方式自动实现,其性能优于锁。
当涉及到事件的线程安全性时,您需要更加小心的是你如何调用它们。请参阅Eric Lippert的帖子 这里.
触发此事件的标准模式为:
Action temp = Foo; if (temp != null) temp();