我对此主题感到非常困惑 - 读取/切换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
会输入帮助吗?
答案 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
变量。