在C#中访问布尔字段原子吗?特别是,我是否需要锁定:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
在C#中访问布尔字段原子吗?特别是,我是否需要锁定:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
Answers:
Interlocked.Add(ref myInt);
例如?
i++
等于i=i+1
,表示您先进行原子读取,然后进行加法,然后进行原子写入。另一个线程可以i
在读取之后但在写入之前进行修改。例如i++
,在同一线程上同时执行的两个线程可能碰巧同时读取(并因此读取相同的值),向其添加一个,然后都写入相同的值,实际上仅添加一次。Interlocked.Add可以防止这种情况。通常,仅当写入一个线程但读取多个线程时,类型为原子的事实才有用。
布尔访问确实是原子的,但这还不是全部。
您不必担心读取“未完全写入”的值-尚不清楚在任何情况下对bool可能意味着什么-但您必须担心处理器缓存,至少在以下情况下需要担心:时间是一个问题。如果在内核A上运行的线程#1具有您的_bar
in缓存,并且_bar
被在另一个内核上运行的线程#2更新,则线程#1将不会立即看到更改,除非您添加锁定,声明_bar
为volatile
或显式插入Thread.MemoryBarrier()
来使无效。缓存的值。
var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
我使用的方法(我认为是正确的)是
volatile bool b = false;
.. rarely signal an update with a large state change...
lock b_lock
{
b = true;
//other;
}
... another thread ...
if(b)
{
lock b_lock
{
if(b)
{
//other stuff
b = false;
}
}
}
目标基本上是避免每次迭代都必须重复锁定对象,而只是为了提供大量很少发生的状态改变信息而检查是否需要锁定它。我认为这种方法行得通。而且,如果需要绝对一致性,我认为在bool上使用volatile较为合适。
lock()
,就不需要volatile
。