在C#中是bool读/写原子吗?

dbk*_*bkk 77 .net c# concurrency boolean locking

在C#中访问bool字段原子?特别是,我需要锁定:

class Foo
{
   private bool _bar;

   //... in some function on any thread (or many threads)
   _bar = true;

   //... same for a read
   if (_bar) { ... }
}
Run Code Online (Sandbox Code Playgroud)

Lar*_*nal 109

是.

以下数据类型的读取和写入是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型.

C#语言规范中找到.

编辑:理解volatile关键字可能也值得.

  • 重新指定它的指针本身是原子的(即Foo foo1 = foo2; (10认同)
  • @configurator:问题是你到底想要什么.很容易让无锁程序出错; 所以除非你真的需要它,否则最好使用更简单的框架(例如TPL).换句话说,"volatile"并没有错,而是一个棘手的(即最好是避免的)代码的标志.OP并没有真正说出他想要的东西,我只是犹豫*推荐*不稳定的willy-nilly. (4认同)
  • WAW.这是一个危险的措辞,对于C++人来说,原子意味着任何读写也都被相应的内存栅栏所包围.在C#中肯定不是这种情况.因为否则性能会很糟糕,因为它对所有变量都是强制性的.这里的原子用C#表示,当读或写最终发生时,似乎意味着**,它们保证永远不会处于破碎状态**.但它没有说什么时候"最终". (4认同)
  • @MikedeKlerk读写是原子的,但是是分开的.`i ++`等于`i = i + 1`,意思是你做原子读,然后加,然后原子写.另一个线程可以在读取之后但在写入之前修改`i`.例如,在同一个i上同时执行`i ++`的两个线程可能会同时读取(因此读取相同的值),向其中添加一个然后写入相同的值,实际上只添加一次.Interlocked.Add阻止了这一点.作为一般规则,类型是原子的这一事实只有在只有一个线程写入但许多线程读取时才有用. (4认同)
  • 如果对int和long的写入是原子的,那么在使用Interlocked.Add(ref myInt);时例如? (2认同)

Dro*_*per 47

如上所述bool是原子的,但你仍需要记住它还取决于你想用它做什么.

if(b == false)
{
    //do something
}
Run Code Online (Sandbox Code Playgroud)

不是原子操作意味着在当前线程在if语句之后执行代码之前b值可能会发生变化.

  • +1用于提醒人们这个经常被忽视的事实 (6认同)

McK*_*eG1 27

bool访问确实是原子的,但这不是全部.

您不必担心读取"未完全写入"的值 - 在任何情况下都不清楚boo可能意味着什么 - 但您必须担心处理器缓存,至少在时机是一个问题.如果在核心A上运行的线程#1具有您_bar的缓存,并且_bar由在另一个核心上运行的线程#2更新,则线程#1将不会立即看到更改,除非您添加锁定,声明_barvolatile或显式插入调用以Thread.MemoryBarrier()使其无效缓存的价值.

  • MemoryBarrier()不会使任何处理器缓存无效.在某些体系结构中,允许处理器重新排序对主存储器的读取和写入以提高性能.只要从单个线程的角度来看,重新排序就可能发生,语义保持不变.MemoryBarrier()请求处理器限制重新排序,以便在屏障之前发出的内存操作不会以在屏障之后结束的方式重新排序. (3认同)