不检查静态字典线程安全中的键是否存在? Resharper认为不是
Is not checking key existence in a static dictionary thread-safe? Resharper thinks it's not
Resharper 建议将 return dic.Contains("v1");
包装在 lock 语句中说“该字段有时在同步块内使用,有时在没有同步的情况下使用":
public class MyClass
{
private static Dictionary<string, string> _dic = new Dictionary<string, string>();
protected bool V1Exist()
{
return dic.Contains("v1");
}
}
但是我不明白为什么示例中需要 lock。对我来说它看起来很安全。请指教
众所周知,字典不是线程安全的,因此您应该同步写入和读取。但是,如果您想了解可能出错的具体示例 - 考虑这个小应用程序:
static void Main(string[] args) {
var dict = new Dictionary<int, int>();
dict.Add(0, 0);
new Thread(() => {
for (int i = 1; i < int.MaxValue; i++) {
lock (dict) {
dict.Add(i, i);
dict.Remove(i);
}
}
}).Start();
new Thread(() => {
while (true) {
if (!dict.ContainsKey(0))
throw new Exception("cannot happen?");
}
}).Start();
Console.ReadKey();
}
我们创建了一个字典,其中包含一个带有键 0
的条目,然后我们 运行 两个线程。第一个线程不断地向字典添加和删除键,但请注意它不会删除键为 0 的项目。键为 0 的项目始终存在。
第二个线程不断检查是否有键为 0 的项目,如果没有则抛出异常。您可能认为这永远不会发生,因为我们永远不会删除键为 0 的项目,但事实并非如此。如果您 运行 这个应用程序,它几乎会立即抛出 "cannot happen?" 异常。如果你在 ContainsKey
附近加锁——这永远不会发生。
所以简而言之,如果您没有正确地同步对非线程安全结构的访问,甚至是读取,事情可能会变得非常糟糕。您甚至可能没有注意到这一点,并且很难调试此类问题,因为应用程序可能表现得一切正常。
Resharper 建议将 return dic.Contains("v1");
包装在 lock 语句中说“该字段有时在同步块内使用,有时在没有同步的情况下使用":
public class MyClass
{
private static Dictionary<string, string> _dic = new Dictionary<string, string>();
protected bool V1Exist()
{
return dic.Contains("v1");
}
}
但是我不明白为什么示例中需要 lock。对我来说它看起来很安全。请指教
众所周知,字典不是线程安全的,因此您应该同步写入和读取。但是,如果您想了解可能出错的具体示例 - 考虑这个小应用程序:
static void Main(string[] args) {
var dict = new Dictionary<int, int>();
dict.Add(0, 0);
new Thread(() => {
for (int i = 1; i < int.MaxValue; i++) {
lock (dict) {
dict.Add(i, i);
dict.Remove(i);
}
}
}).Start();
new Thread(() => {
while (true) {
if (!dict.ContainsKey(0))
throw new Exception("cannot happen?");
}
}).Start();
Console.ReadKey();
}
我们创建了一个字典,其中包含一个带有键 0
的条目,然后我们 运行 两个线程。第一个线程不断地向字典添加和删除键,但请注意它不会删除键为 0 的项目。键为 0 的项目始终存在。
第二个线程不断检查是否有键为 0 的项目,如果没有则抛出异常。您可能认为这永远不会发生,因为我们永远不会删除键为 0 的项目,但事实并非如此。如果您 运行 这个应用程序,它几乎会立即抛出 "cannot happen?" 异常。如果你在 ContainsKey
附近加锁——这永远不会发生。
所以简而言之,如果您没有正确地同步对非线程安全结构的访问,甚至是读取,事情可能会变得非常糟糕。您甚至可能没有注意到这一点,并且很难调试此类问题,因为应用程序可能表现得一切正常。