gpt4 book ai didi

c# - 事件引发和阅读 .net 4.5 中的介绍

转载 作者:行者123 更新时间:2023-12-03 12:49:33 25 4
gpt4 key购买 nike

我有与此 MSDN 杂志相关的问题 article .

Read Introduction As I just explained, the compiler sometimes fuses multiple reads into one. The compiler can also split a single read into multiple reads. In the .NET Framework 4.5, read introduction is much less common than read elimination and occurs only in very rare, specific circumstances. However, it does sometimes happen.

public class ReadIntro {
private Object _obj = new Object();
void PrintObj() {
Object obj = _obj;
if (obj != null) {
Console.WriteLine(obj.ToString());
// May throw a NullReferenceException
}
}
void Uninitialize() {
_obj = null;
}
}

If you examine the PrintObj method, it looks like the obj value will never be null in the obj.ToString expression. However, that line of code could in fact throw a NullReferenceException. The CLR JIT might compile the PrintObj method as if it were written like this:

void PrintObj() {
if (_obj != null) {
Console.WriteLine(_obj.ToString());
}
}

但这不是一种处理事件的模式吗?!

void RaiseEvent()
{
var myEvent = MyEvent;
if (myEvent != null)
{
myEvent(this, EventArgs.Empty);
}
}

我是否错过了一些重要的事情?

最佳答案

这篇文章也让我感到困惑,我做了一些研究。我发现了两种思想流派。

1。有人说该模式是安全的

因为 CLR 2.0 内存模型比 1.x 更严格并且禁止它。

"Reads and writes cannot be introduced", MSDN Magazine (Oct 05), article Understand the Impact of Low-Lock Techniques in Multithreaded Apps.

"the .NET memory model prohibits it [read introduction] for ordinary variables referring to GC heap memory", Joe Duffy, book Concurrent Programming on Windows, pp517-8.

[注:Joe Duffy 基本上说了同样的话,但留下了在堆栈上读取介绍的可能性,该堆栈不共享,因此安全]

我发现那些“.NET 2.0内存模型”的解释很奇怪。我已阅读 2012 ECMA CLI 规范以及 C# 标准,没有发现任何引用禁止读取引入的声明。他们不太可能在2.0和4之间削弱内存模型。(??)

另一方面,我相信 JIT 团队了解这些模式并且不会破坏它们,至少在 x86 上......但是说这与说它在标准中不同。团队决策可能会在未来或在其他平台上发生变化。

编辑不要错过下面 Eric Lippert 的评论:“无需阅读介绍”是 Microsoft CLI 实现的 promise 。 ECMA 标准中没有任何关于它的内容,当使用其他实现(例如 Mono)时,所有的赌注都会被取消。 结束编辑

2。有人说这不安全

具体来说:您引用的文章中的伊戈尔·奥斯特洛夫斯基 (Igor Ostrovsky),以及本博客文章评论内的讨论中的斯蒂芬·托布 (Stephen Toub):http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx .

基本上,他们说读引入或消除是一种常见的编译器优化,如果不改变单线程行为,C# 和 JIT 都可以这样做。

[注:Eric Lippert 表示 C# 编译器目前没有进行此类优化。]

请注意,Igor 似乎意识到 JIT 相当保守,并在文章中明确指出,您的示例代码在 x86-x64 上的 .NET 4.5 中不会中断。另一方面,他表示在其他情况下它可能会崩溃,但没有具体说明它是否是更复杂的代码模式、 future 或过去的 .net 版本或其他平台。

解决方案

如果你想100%安全,解决方案是使用 volatile 读取。 volatile 读取和写入被 C# 标准定义为副作用,因此无法引入或删除它们。

ECMA CLI 标准有一个类似的明确声明,即不删除 volatile 读取和写入。

关于线程安全事件的说明

正如许多人指出的那样,线程安全不仅仅是事件引发代码。您的事件处理程序应该准备好在取消订阅后被调用。

我同意 Hans Passant 的观点,最好的指导是“不要这样做”,但有时你需要这样做。在这些情况下,只需确保您的事件处理程序代码也是线程安全的。在这些情况下,您可能还需要考虑一种更简单的基于锁的同步方法。

关于c# - 事件引发和阅读 .net 4.5 中的介绍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16162745/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com