C#和bool的线程安全性

Pat*_*ski 16 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; } }
Run Code Online (Sandbox Code Playgroud)

它们都是线程安全的吗?

编辑

从我所读到的(点击)bool的原子性不保证它将是线程安全的.那么会volatile输入帮助吗?

Yur*_*ura 24

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

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

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

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

因此,在处理多线程时,您总是必须在有价值的资源上使用一些线程同步技术.

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

  • *值可能已损坏*否,值不能被破坏(如"非法/未定义值转换").你可能会得到陈旧("旧")的价值观. (3认同)
  • 我的意思是“腐败”的方式“不是应该的或你期望的”。绝对不是内存损坏意义上的损坏:) (3认同)

lil*_*lo0 14

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

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

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一定要在所有地方使用Property,永远不要int直接访问变量.

  • 在“get”中为什么不使用 [`Interlocked.Read(ref _threadSafeBoolBackValue) == 1`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.interlocked.read?view =netframework-4.8#remarks) 而不是 `Interlocked.CompareExchange`? (2认同)
  • 很简单,因为哪里没有 Interlocked.Read for `int` 参数。如果您确实想使用“Interlocked.Read”方法,您可以将值类型改回“long”。 (2认同)

Ron*_*ovi 10

不,不是。但解决方案很简单。为了使 bool (或实际上的任何东西)线程安全,很容易使用像这样的lock语句:

object locker = new object();
protected bool _somebool;
public bool Somebool
{
    get
    {
        lock (locker)
            return _somebool;
    }
    set
    {
        lock (locker)
            _somebool = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

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