我正在尝试了解对字段的线程安全访问。为此,我实现了一些测试示例:
class Program
{
public static void Main()
{
Foo test = new Foo();
bool temp;
new Thread(() => { test.Loop = false; }).Start();
do
{
temp = test.Loop;
}
while (temp == true);
}
}
class Foo
{
public bool Loop = true;
}
正如预期的那样,有时它不会终止。我知道这个问题可以用 volatile 关键字或锁来解决。我认为我不是 Foo 类的作者,所以我不能让字段变得不稳定。我尝试使用锁:
public static void Main()
{
Foo test = new Foo();
object locker = new Object();
bool temp;
new Thread(() => { test.Loop = false; }).Start();
do
{
lock (locker)
{
temp = test.Loop;
}
}
while (temp == true);
}
这似乎解决了这个问题。只是为了确保我将循环移动到锁 block 内:
lock(locker)
{
do
{
temp = test.Loop;
}
while (temp == true);
}
并且...程序不再终止。
这让我很困惑。 lock 不提供线程安全访问吗?如果不是,如何安全地访问非 volatile 字段? 我可以使用 VolatileRead(),但它不适用于任何情况,例如原始类型或属性。 我认为 Monitor.Enter 可以完成这项工作,我说得对吗?我不明白它是如何工作的。
最佳答案
这段代码:
do
{
lock (locker)
{
temp = test.Loop;
}
}
while (temp == true);
因为 lock
的副作用而起作用:它导致 'memory-fence' .实际的锁定在这里无关紧要。等效代码:
do
{
Thread.MemoryBarrier();
temp = test.Loop;
}
while (temp == true);
你在这里试图解决的问题不完全是线程安全的,它是关于变量(陈旧数据)的缓存。
关于c# - 锁定部分是否始终保证线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23460916/