构造函数可以被抢先一步吗?

ose*_*ose 10 c# multithreading

是否有可能在C#中抢占构造函数?

例如,考虑代码:

public class A
{
    public bool ready = true;

    public A()
    {
        ready = false; // Point #1
        // Other initialization stuff
        ready = true; // Point #2
    }
}
Run Code Online (Sandbox Code Playgroud)

在代码中的其他地方,两个线程可以访问类型A的变量,第一个线程调用在#1点抢占的构造函数.然后第二个线程测试ready并发现它仍然是真的因此它做了一些坏事.

这种情况可能吗?

进一步来说:

  1. 构造函数可以被抢先一步吗?
  2. 如果是这样,这是否意味着应该有lock构造函数中的同步代码?
  3. 在构造函数退出后,构造的对象是否仅分配给共享变量,从而完全避免了这个问题?

小智 5

我不认为接受的答案是正确的.伊戈尔·奥斯特罗夫斯基的" 理论与实践中的C#记忆模型 "(这里的第2部分)彻底解释了这些问题,其中一个例子说明了你所询问的内容.

它给出了代码

class BoxedInt2
{
  public readonly int _value = 42;
  void PrintValue()
  {
    Console.WriteLine(_value);
  }
}

class Tester
{
  BoxedInt2 _box = null;
  public void Set() {
    _box = new BoxedInt2();
  }
  public void Print() {
    var b = _box;
    if (b != null) b.PrintValue();
  }
}
Run Code Online (Sandbox Code Playgroud)

并注意到:

由于BoxedInt实例未正确发布(通过非易失性字段_box),调用Print的线程可能会观察到部分构造的对象!再次,使_box字段不稳定将解决问题.

我强烈鼓励阅读整篇文章,这是一篇非常有用的读物​​.