【发布时间】:2016-02-22 17:23:57
【问题描述】:
我正在寻找其他信息,了解为什么 Microsoft 建议在编写事件访问器语法时锁定对象。微软的代码示例如下所示,建议链接到。
我理解关于锁定一段代码以控制多线程访问它的一般概念,但是我正在寻找在 Microsoft 示例的上下文中编写自定义事件访问器逻辑时这些问题发挥作用的具体原因显示。
以下示例展示了如何实现自定义添加和删除 事件访问器。虽然你可以替换里面的任何代码 访问者,我们建议您在添加或 删除一个新的事件处理方法。
event EventHandler IDrawingObject.OnDraw
{
add
{
lock (PreDrawEvent)
{
PreDrawEvent += value;
}
}
remove
{
lock (PreDrawEvent)
{
PreDrawEvent -= value;
}
}
}
~通过https://msdn.microsoft.com/en-us/library/bb882534.aspx?f=255&MSPPError=-2147217396
【问题讨论】:
-
能否在引发事件的同时移除事件句柄?会猜测这可能会导致空引用异常。
-
我不是 100% 确定,但我认为这是因为事件基本上是多播委托。因此,当您添加/删除处理程序时,实际上会创建一个 new 委托。所以,它实际上是一个两步操作:生成新的委托,并分配给现有的变量。如果多个线程同时(取消)订阅,则会引入一个竞争条件窗口。
-
进一步说明,由于上述原因,我认为锁定您正在修改的事件将是不好的形式。拥有一个专用的锁对象似乎更明智。
-
@C.Knight - 这是一种可能性,尽管它与上述逻辑没有任何关系。您应该始终将事件分配给局部变量,然后在尝试调用它之前检查它是否为空。
-
+= 不是原子的。这是一个 3 步过程,它使您的 PreDrawEvent 处于无效状态,直到所有 3 个步骤完成:(1) 将现有 PreDrawEvent 复制到寄存器中,(2) 附加到寄存器中的事件,(3) 将新附加的列表复制回变量...由exactly the guy you'd expect在这里回答...
标签: c# multithreading events event-handling