c# - 锁定部分是否始终保证线程安全?

标签 c# thread-safety volatile critical-section

我正在尝试了解对字段的线程安全访问。为此,我实现了一些测试示例:

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/

相关文章:

使用 Process() 和多线程的 Swift 命令行工具在一定数量的执行轮次(~3148)后崩溃

c# - Random.Next() 总是返回 0

c# - 共享内存是否可以在某个线程中更新,而它的值仍然对主线程不可见?

c# - 从现有数据库和 Fluent NHibernate 自动映射生成 C# 实体

c# - Xamarin 崩溃 : System. MissingMethodException : Method not found: void . ResourceLoadingQuery.set_Instance(object)

go - 为什么 os/exec.CombinedOutput() 没有竞争条件?

c++ - 从语法的角度来看, "volatile"关键字在 C++ 函数中有多少次用法?

c# - 如何创建包含 CRL 分发点的自签名证书

c# - 我的用户控件上的所有基本属性是否都需要依赖属性?

Java 重新排序和不稳定问题