静态变量的线程安全初始化

Rao*_*bin 15 c# singleton multithreading

我一直在使用这种模式来初始化我的类中的静态数据.它看起来对我来说是安全的,但我知道细微的线程问题是多么微妙.这是代码:

public class MyClass // bad code, do not use
{
    static string _myResource = "";
    static volatile bool _init = false;
    public MyClass()
    {
        if (_init == true) return;
        lock (_myResource)
        {
            if (_init == true) return;
            Thread.Sleep(3000); // some operation that takes a long time 
            _myResource = "Hello World";
            _init = true;
        }
    }
    public string MyResource { get { return _myResource; } }
}
Run Code Online (Sandbox Code Playgroud)

这里有洞吗?也许有一种更简单的方法可以做到这一点.

更新:共识似乎是静态构造函数是要走的路.我使用静态构造函数提出了以下版本.

public class MyClass
{
    static MyClass() // a static constructor
    {
        Thread.Sleep(3000); // some operation that takes a long time 
        _myResource = "Hello World";
    }

    static string _myResource = null;

    public MyClass() { LocalString = "Act locally"; } // an instance constructor

    // use but don't modify
    public bool MyResourceReady { get { return _myResource != null; } }
    public string LocalString { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我希望这更好.

小智 12

您可以使用静态构造函数初始化静态变量,C#guarantee仅在每个AppDomain中调用一次.不确定你是否考虑过它们.

所以你可以读到这个:http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx(静态构造函数)

而这:C#静态构造函数线程是否安全?


max*_*max 6

执行lock()_myResource并改变它里面lock()的语句似乎是一个坏主意.考虑以下工作流程

  1. 线程1调用MyClass().
  2. _init = true;分配后,执行在行之前停止_myResource.
  3. 处理器切换到线程2.
  4. 线程2调用MyClass().由于_init仍然false和refrence _myResource更改,它成功进入lock()语句块.
  5. _init仍然是false,所以线程2重新分配_myResource.

解决方法:创建静态object并锁定此对象而不是初始化资源:

private static readonly object _resourceLock = new object();

/*...*/

lock(_resourceLock)
{
    /*...*/
}
Run Code Online (Sandbox Code Playgroud)