C#和bool的线程安全性

时间:2015-04-02 11:35:10

标签: c# multithreading thread-safety

我对此主题感到非常困惑 - 读取/切换bool值是否是线程安全的。

    // case one, nothing
    private bool v1;
    public bool V1 { get { return v1; } set { v1 = value; } }

    // case two, with Interlocked on set
    private int v2;
    public int V2 { get { return v2; } set { Interlocked.Exchange(ref v2, value); } }

    // case three, with lock on set
    private object fieldLock = new object();
    private bool v3;
    public bool V3 { get { return v3; } set { lock (fieldLock) v3 = value; } }

他们都是线程安全的吗?

修改

从我读过的内容(click)bool的原子性并不能保证它是线程安全的。那么volatile会输入帮助吗?

2 个答案:

答案 0 :(得分:22)

不,并非所有这些都是线程安全的。

案例一实际上并不完全是线程安全的,或者更好的说法 - 它根本不是线程安全的。即使使用boolean的操作是原子的,变量值也可以存储在缓存中,因此,如在多核CPU中每个核心都有自己的缓存,值可能会被破坏。

更进一步,编译器和CPU可以执行一些内部优化,包括指令重新排序,这可能会对程序的逻辑产生不利影响。

您可以添加volatile关键字,以通知编译器该字段在多线程上下文中使用。它将修复缓存和指令重新排序的问题,但不会给你真正的“线程安全”代码(因为写操作仍然不会同步)。另外volatile不能应用于局部变量。

因此,在处理多线程时,您总是必须在宝贵的资源上使用一些线程同步技术。

有关更多信息,请阅读this回答,其中对不同技术有更深入的解释。 (例如,约有int,但并不重要,它描述了一般方法。)

答案 1 :(得分:11)

有点迟,但应该对其他人有用。

您可以通过以下方式实现自己的线程安全布尔值:

// default is false, set 1 for true.
private int _threadSafeBoolBackValue = 0;

public bool ThreadSafeBool
{
    get { return (Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 1) == 1); }
    set
    {
        if (value) Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 0);
        else Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 0, 1);
    }
}

请务必在任何地方使用Property,不要直接访问int变量。