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>
的线程安全了。
我对这个问题很困惑 - 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>
的线程安全了。