我在Microsoft的C#Reference中已经阅读了以下内容:
lock(“myLock”)是一个问题,因为该过程中的任何其他代码 使用相同的字符串,将共享相同的锁。
究竟是什么意思?
以下代码是否无法正常工作? (我希望ReadyCount
是一致的)
public class Calculator
{
public int ReadyCount { get; private set; }
public void IncreaseReadyCount()
{
lock ("ReadyCount")
{
ReadyCount++;
}
}
public void Calculate()
{
Parallel.ForEach(list, litItem =>
{
IncreaseReadyCount();
});
}
}
答案 0 :(得分:4)
问题是:该锁的范围是什么? 你无法告诉;它至少等同于<{1}}类型的静态/全局,但它也可能由任何其他代码偶然共享碰巧做了Calculator
(给出了实习版本)和ldstr 'ReadyCount'
(或使用lock
等)。不太可能,但风险很大。
更重要的是,对于休闲读者而言并不是显而易见的,这是一个问题。如果你想要它是一个静态/全局锁,那么这相当于你的代码,但更明显,没有不相关的代码冒险锁定的风险:
Monitor
有了这个,至少它显然正在做什么。
就个人而言,我很想使用static readonly object readyCountLock = new object();
...
lock(readyCountLock) {...}
:)
答案 1 :(得分:3)
除了Marc所说的,在现实生活中,人们会尝试锁定可能未被实现的字符串,例如从数据库记录中锁定某些键。如果您锁定实习字符串,则仅锁定字符串(种类)。但请考虑一下:
// not interned, but both strings represent "test"
string lock1 = new string(new char[] { 't', 'e', 's', 't' });
string lock2 = new string(new char[] { 't', 'e', 's', 't' });
Task.Run(() =>
{
lock (lock1) {
Console.WriteLine("1 entered");
Thread.Sleep(1000);
}
});
Task.Run(() =>
{
lock (lock2)
{
Console.WriteLine("2 entered");
Thread.Sleep(1000);
}
});
此代码立即执行两个“受保护”部分,因为尽管两个字符串都是“测试” - 但它们是不同的实例。所以锁定常量字符串是不可靠的,因为它是全局的,你永远不知道哪些代码使用了这样的“锁定”,并且锁定字符串变量是危险的,因为它可能根本不起作用。
回答关于锁定ReadyCount.ToString()
的评论。这正是人们在现实生活中尝试这样做的方式(其中ReadyCount
是数据库记录的某些属性或类似)。我通过ReadyCount
猜你的意思是一些数字,而不是真正的字符串(否则调用ToString
毫无意义)。不,这也很糟糕,因为:
int readyCount = 1;
string lock1 = readyCount.ToString();
string lock2 = readyCount.ToString();
bool same = Object.ReferenceEquals(lock1, lock2);
// nope, not the same, lock will not work