我一直在使用这种模式初始化我的类中的静态数据。它看起来对我来说是安全的,但我知道细微的线程问题是多么微妙。这是代码:
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; } }
}
这里有漏洞吗?也许有一种更简单的方法可以做到这一点。
更新:共识似乎是静态构造函数是要走的路。我使用静态构造函数提出了以下版本。
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; }
}
我希望这更好。
答案 0 :(得分:12)
您可以使用静态构造函数初始化静态变量,C#guarantee仅在每个AppDomain中调用一次。不确定你是否考虑过它们。
所以你可以读到这个:http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx(静态构造函数)
答案 1 :(得分:6)
在lock()
上执行_myResource
并在lock()
语句中更改它似乎是一个坏主意。
请考虑以下工作流程:
MyClass()
。_init = true;
后立即在行_myResource
之前停止执行。MyClass()
。由于_init
仍为false
且参考_myResource
已更改,因此会成功输入lock()
语句块。_init
仍为false
,因此主题2重新分配_myResource
。解决方法:创建静态object
并锁定此对象而不是初始化资源:
private static readonly object _resourceLock = new object();
/*...*/
lock(_resourceLock)
{
/*...*/
}
答案 2 :(得分:3)
你的课不安全:
这应该适合你:
public class MyClass
{
static readonly object _sync = new object();
static string _myResource = "";
static volatile bool _init = false;
public MyClass()
{
if (_init == true) return;
lock (_sync)
{
if (_init == true) return;
Thread.Sleep(3000); // some operation that takes a long time
_myResource = "Hello World";
_init = true;
}
}
public string MyResource
{
get
{
MyClass ret; // Correct
lock(_sync)
{
ret = _myResource;
}
return ret;
}
}
}
<强>更新强>
正确,不应该直接返回静态资源...我已经相应地更正了我的例子。
答案 3 :(得分:1)
根据您的使用情况(即如果线程不需要使用此变量将信息相互传递),将成员变量标记为[ThreadStatic]
可能是一种解决方案。
请参阅here。
答案 4 :(得分:0)
static string _myResource = "";
...
public MyClass()
{
...
lock (_myResource)
{
}
}
由于string interning,您不应该锁定字符串文字。如果锁定字符串文字并且多个类使用该字符串文字,那么您可能正在共享该锁。这可能会导致意外行为。