相关疑难解决方法(0)

阅读C#简介 - 如何防范它?

MSDN杂志中的一篇文章讨论了Read Introduction的概念,并给出了一个可以被它破坏的代码示例.

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

注意这个"可能抛出NullReferenceException"的注释 - 我从来不知道这是可能的.

所以我的问题是:我如何防止阅读介绍?

我还非常感谢编译器决定引入读取的确切解释,因为该文章不包括它.

.net c# multithreading

24
推荐指数
2
解决办法
1020
查看次数

事件和多线程再一次

我担心看似标准的前C#6模式的正确性可以解雇事件:

EventHandler localCopy = SomeEvent;
if (localCopy != null)
    localCopy(this, args);
Run Code Online (Sandbox Code Playgroud)

我已经阅读了Eric Lippert的事件和比赛,并且知道调用过时的事件处理程序还有一个问题,但我担心的是,是否允许编译器/ JITter优化掉本地副本,有效地将代码重写为

if (SomeEvent != null)
    SomeEvent(this, args);
Run Code Online (Sandbox Code Playgroud)

有可能NullReferenceException.

根据C#语言规范,§3.10,

必须保留这些副作用的顺序的关键执行点是对volatile字段(第10.5.3节),锁语句(第8.12节)以及线程创建和终止的引用.

- 所以在上述模式中没有关键执行点,优化器也不受此限制.

Jon Skeet(2009年)的相关答案指出

由于条件的原因,JIT不允许在第一部分中执行您正在讨论的优化.我知道这是作为一个幽灵提出的,但它无效.(我刚才和Joe Duffy或Vance Morrison一起检查过;我不记得是哪一个.)

- 但是评论引用了这篇博客文章(2008年):事件和线程(第4部分),它基本上说CLR 2.0的JITter(可能是后续版本?)不能引入读取或写入,所以一定没有问题在Microsoft .NET下.但这似乎与其他.NET实现没有任何关系.

[旁注:我没有看到不引入读取证明了所述模式的正确性.难道JITter只是看到一些SomeEvent其他局部变量的陈旧值并优化其中一个读取,而不是另一个?完全合法,对吗?]

此外,这篇MSDN文章(2012年):Igor Ostrovsky的理论与实践中的C#记忆模型陈述如下:

非重新排序优化某些编译器优化可能会引入或消除某些内存操作.例如,编译器可能用一次读取替换字段的重复读取.类似地,如果代码读取字段并将值存储在局部变量中然后重复读取变量,则编译器可以选择重复读取该字段.

因为ECMA C#规范不排除非重新排序的优化,所以它们可能是允许的.实际上,正如我将在第2部分中讨论的那样,JIT编译器确实执行了这些类型的优化.

这似乎与Jon Skeet的答案相矛盾.

由于现在C#不再是Windows语言,因此问题在于,模式的有效性是否是当前CLR实现中有限的JITter优化的结果,或者是语言的预期属性.

所以,问题是:从C#-the-language的角度来看,正在讨论的模式是否有效?(这意味着是否需要语言编译器/运行时来禁止某种优化.)

当然,欢迎就该主题提出规范性参考.

.net c# multithreading memory-model language-lawyer

13
推荐指数
1
解决办法
362
查看次数

在多线程环境中引发事件

从 .NET 4.0 开始,自动生成的添加/删除事件处理程序是线程安全的(此处此处)。因此,将其侦听器注册到公开事件的客户端可以从多个线程同时进行,而不会发生竞争。

但是如果我想以线程安全的方式触发事件怎么办?推荐的做法似乎如下(这里):

public event EventHandler MyEvent;
protected void OnMyEvent(EventArgs e)
{
    EventHandler myEvent = MyEvent;
    if (myEvent != null)
    {
        myEvent(this, e);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在阅读了有关 .NET 内存模型的内容后(例如 MSDN 杂志2012-122013-01),我不再认为这是正确的。我担心的是编译器可能会引入内存读取,因此上面的代码可能会被 JIT-ted 变成这样:

public event EventHandler MyEvent;
protected void OnMyEvent(EventArgs e)
{
    // JIT removed the local variable and introduced two memory reads instead.
    if (MyEvent != null)
    {
        // A race condition may cause the following line to …
Run Code Online (Sandbox Code Playgroud)

.net c# concurrency multithreading memory-model

5
推荐指数
1
解决办法
1401
查看次数