C#中哪些操作是原子的?

Eri*_*ric 51 .net c# multithreading atomic

是否有系统的方法来了解C#中的操作是否是原子操作?或者是否有任何一般指导方针或经验法则?

Pet*_*hie 34

更完整/更详细的内容:

对32位值类型的读取和写入是原子的:这包括以下内在值(struct)类型:bool, char, byte, sbyte, short, ushort, int, uint, float.以下类型(以及其他类型)不保证是原子的:decimal, double, long, ulong.

例如

int x;
x = 10; // atomic
decimal d;

d = 10m; // not atomic
Run Code Online (Sandbox Code Playgroud)

引用赋值也是一个原子操作:

private String _text;
public void Method(String text)
{
  _text = text; // atomic
}
Run Code Online (Sandbox Code Playgroud)

  • 不严格正确 - 如果您的本机字大小为64位的系统(例如运行64位版本的Windows的x64处理器),64位值(长)也是原子的 (17认同)
  • @ChrisShain,您是正确的,规范并没有说它们是“不是”原子的或“从不”原子的,我已经澄清了我的答案(这并不意味着它们永远不会是原子的,只是不能保证)。但是,您必须为x64进行编译以确保确实如此。如果不针对x64进行编译,则代码可以在x86中运行,因此不是原子的。因此,您必须假定它不是原子的,并使用lock或Monitor.Enter / Exit以确保它是原子访问的。 (2认同)

Chr*_*ain 31

是.阅读CLI规范:http://www.ecma-international.org/publications/standards/Ecma-335.htm.例如:

I.12.6.6原子读写

符合要求的CLI应保证当对位置的所有写访问都是原子时,对正确对齐的内存位置的读写访问不大于本机字大小(native int类型的大小)是原子的(参见§I.12.6.2).大小相同.原子写入除了写入之外不得改变任何位.除非使用显式布局控制(请参阅分区II(控制实例布局))来更改默认行为,否则应正确对齐不大于自然字大小(本机int的大小)的数据元素.对象引用应被视为存储在本机字大小中.

[注意:不保证内存的原子更新(读 - 修改 - 写),除了为此目的提供的方法作为类库的一部分(参见Partition IV).在不支持直接写入小数据项的硬件上进行原子读取/修改/写入时,需要对"小数据项"(不大于本机字大小的项)进行原子写入.结束说明]

[注意:当native int的大小为32位时,没有保证对8字节数据的原子访问,即使某些实现在数据在8字节边界上对齐时可能执行原子操作.结束说明]

关于64位长的问题,Eric Lippert在这里回答:http://blogs.msdn.com/b/ericlippert/archive/2011/05/31/atomicity-volatility-and-immutability-are-different-part- two.aspx

CLI规范实际上提供了更强的保证.CLI保证读取和写入处理器的自然指针大小的大小(或更小)的值类型的变量是原子的; 如果您在64位版本的CLR中在64位操作系统上运行C#代码,则64位双精度和长整数的读写也保证是原子的.C#语言不保证,但运行时规范确实如此.(如果您在某些环境中运行C#代码,而某些环境尚未通过CLI的某些实现实现,那么您当然不能依赖该保证;如果您想知道它们提供的保证,请联系卖给您运行时的供应商.)

关于原子访问的另一个微妙之处在于,当读取或写入的变量与存储器中的正确位置对齐时,底层处理器仅保证原子性.最终,变量将被实现为指向某处内存的指针.在32位操作系统上,该指针必须可被4整除,以便保证读或写是原子的,而在64位操作系统上,它必须可被8整除.


Sec*_*cko 7

从CLI规范,您可以到这里:

"符合标准的CLI应保证对正确对齐的内存位置的读写访问权限不大于本机字大小(native int类型的大小)是原子的..."

这里的C#规范的第12.5节:

"以下数据类型的读写应该是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference types."另外:"......不能保证原子读取 - 修改 - 写,例如在增加或减少的情况下."

这个使增量操作成为原子.