C# 和 bool 的线程安全

C# and thread-safety of a bool

我对这个问题很困惑 - reading/toggling 布尔值是否是线程安全的。

    // 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 输入帮助吗?

不,不是所有的都是线程安全的。

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

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

您可以添加volatile关键字,以通知编译器该字段用于多线程上下文。它将解决缓存和指令重新排序的问题,但不会为您提供真正的 "thread safe" 代码(因为写操作仍然不会同步)。另外 volatile 不能应用于局部变量。

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

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

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

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

// 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);
    }
}

请务必在任何地方使用 属性,切勿直接访问 int 变量。

不,不是。但解决方案很简单。 要使 bool(或任何东西,实际上)线程安全,可以很容易地使用 lock 语句,如下所示:

object locker = new object();
protected bool _somebool;
public bool Somebool
{
    get
    {
        lock (locker)
            return _somebool;
    }
    set
    {
        lock (locker)
            _somebool = value;
    }
}

现在您可以享受 <T> 的线程安全了。