注册 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; } }
}

注册 C# 事件是否线程安全

是的,自动实现的事件上的+=-=运算符是原子的(如果库使用自定义事件处理程序,则很容易不是原子的)。摘自 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();