C#对象类型 - 赋值的原子性

时间:2013-08-23 06:32:53

标签: c#

快速提问。低于赋值原子:

object [] table = new object[10]
...
table[3] = 10; //is it atomic ?
...

3 个答案:

答案 0 :(得分:4)

是的,赋值是原子的,因为object是引用类型。

如下面引用的那样,MSDN写入对大多数(不是全部)内置值类型(如下所述)和引用类型都是原子的。 CLI保证读取和写入处理器的自然指针大小的大小(或更小)的值类型的变量是原子的;如果您在64位版本的CLR中在64位操作系统上运行C#代码,则64位双精度和长整数的读写也保证是原子的。 C#语言不保证,但运行时规范确实如此。

MSDN说什么

  

以下数据类型的读写是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型。此外,在先前列表中具有基础类型的枚举类型的读取和写入也是原子的。其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的。除了为此目的而设计的库函数之外,不保证原子读 - 修改 - 写,例如在递增或递减的情况下。

可以看到埃里克本人非常详细的回答here

答案 1 :(得分:3)

我假设OP意味着线程安全'在谈论原子性时。

如果另一个线程可能读取部分写入的值,则写操作不仅仅是原子操作。

如果object [] table是方法的本地,每个线程将获得自己的表,因此对表的任何操作都将是原子的。

继续我假设table在线程之间共享。

OP已将表定义为object的数组。因此table[3] = 10涉及拳击。

即使table[3] = 10代表一串指令,这个操作也是原子的,因为这最终会写出地址'盒装实例(当前CLR实现确实表示使用存储器地址的对象引用)和地址是机器的自然字大小(即32位机器上的32位和64位机器上的64位)。请注意,尽管上述说明基于当前的CLR实现,但参考编写的原子性由规范保证。装箱操作和盒装实例本身是线程的本地操作,因此其他线程无法干扰它。 即使在写入超过单词大小的值(例如Decimal)时,也会采用相同的推理,操作将是原子的(由于装箱)。 这里必须注意的是,只有在写入的值已经以线程安全的方式获得时,上述参数才成立。

如果没有涉及拳击,那么通常的字大小规则写入(或者由于内存对齐而小于字大小的大小)是原子保持。

答案 2 :(得分:2)

我严重怀疑整个术语table[3] = 10;是原子的。虽然对某些数据类型的单个读取或写入是原子数组访问很可能不是。

您的示例的IL代码是

IL_0001:  ldc.i4.s    0A 
IL_0003:  newarr      System.Object
IL_0008:  stloc.0     // table
IL_0009:  ldloc.0     // table
IL_000A:  ldc.i4.3    
IL_000B:  ldc.i4.s    0A 
IL_000D:  box         System.Int32
IL_0012:  stelem.ref

你可以看到索引是在IL_000A加载的,然后int的装箱发生在IL_000D,最后装箱的值存储在IL_0012。

这些指令的每个不一致都可能是原子的,但这并不意味着使table[3] = 10;的指令链成为。