【问题标题】:Event invocation pattern and CLR AMD64 JIT Optimizations事件调用模式和 CLR AMD64 JIT 优化
【发布时间】:2013-10-22 07:20:38
【问题描述】:

我们都知道在多线程环境中处理 .NET 事件时的问题。 其中之一是当我们尝试调用事件而不复制到局部变量时:

if (MyEvent != null)
    MyEvent(this, EventArgs.Empty);

在这种情况下,如果在一个线程检查 MyEvent != null 之后,另一个线程取消订阅事件处理程序,我们可以获得竞争条件。 (然后 MyEvent 试图触发和操作.. NullRefException)

解决方案(由 J.Richter 提出)是将事件处理程序复制到局部变量:

var handler = MyEvent;
if (handler != null)
    handler(this, EventArgs.Empty); 

这很好用,因为

Delegates are immutable; once created, the invocation list of a delegate does not change.

但据我所知AMD64 JIT does some optimizations 可以忽略本地副本并读取事件处理程序的实际值。 (一篇文章很旧,但我找不到任何关于此类问题的实际信息)。

那么,CLR JIT 在这种情况下实际上是如何工作的?会不会有 NullReferenceException?

【问题讨论】:

  • IMO 事件完全不适合多线程环境。
  • @spender 你为什么会这样建议?如果您正确使用事件,事件在线程环境中仍然非常有用。许多线程组件完全基于事件...

标签: c# .net multithreading clr jit


【解决方案1】:

博客文章不完整,它没有讲述他们对此做了什么。它很旧,在 x64 抖动实际发布前一年发布。他们可能在测试时发现了问题。

他关于应该使用 volatile 的断言并非完全不准确。然而,这需要使用 C 编译器来查看问题。或者 x86 抖动实现 volatile 的方式。不幸的是,C# 语言的 volatile 定义严重受损,被随意拉出以处理具有弱内存模型的处理器。 Itanium 是那里的主要麻烦制造者。搞砸了,让乔·达菲完全放弃并declare it evil

他们提出的解决方案相当激进,他们完全消除了对 volatile 的需求,它对代码生成完全没有影响。并且事件触发模式被拯救了,x64 抖动实际上复制并存储了参考。不是在局部变量中,而是在 CPU 寄存器中,x64 有很多。否则为标准优化器功能。

【讨论】:

  • 优化是非法的,还是 CLR 有效地扩展了规范以使这种模式安全?
  • 如果你让 volatile 表达你喜欢的意思,这并不违法。就像博文作者所做的那样。这里不涉及 CLR,这是一个纯粹的抖动细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多