快速问答。在赋值原子下面:
object [] table = new object[10]
...
table[3] = 10; //is it atomic ?
...发布于 2013-08-23 08:15:30
我假设OP在谈论原子性时意味着‘线程安全’。
只有当另一个线程可以读取部分写入值时,写操作才不是原子操作。
如果object [] table是方法的本地对象,那么每个线程都会得到自己的表,因此表上的任何操作都是原子的。
接下来,我假设table是跨线程共享的。
OP将表定义为object的数组。因此,table[3] = 10涉及装箱。
尽管table[3] = 10表示一个指令链,但这个操作是原子的,因为它最终将写入盒式实例的“地址”(当前的CLR实现确实表示使用内存地址的对象引用),并且地址具有机器的自然字长(即32位机器上的32位和64位机器上的64位)。请注意,即使上面的解释是基于当前的CLR实现,原子性的参考写作是保证的规格。装箱操作和装箱实例本身都是线程的本地操作,因此其他线程不可能对此进行干预。根据同样的推理,即使正在编写的值超过单词大小(例如Decimal),操作也应该是原子的(由于装箱)。这里必须注意的是,只有在已以线程安全的方式获得正在写入的值时,上述参数才有效。
如果不涉及装箱,那么word size的通常规则是原子保存(或由于内存对齐而小于单词大小)。
发布于 2013-08-23 06:35:37
是的,赋值是原子的,因为对象是引用类型。
正如下面所提到的,来自MSDN写的引用是原子的,对于大多数(不是所有) buil-in值类型(下面提到)和引用类型。CLI保证读取和写入值类型的变量(即处理器的自然指针大小的大小(或更小))是原子的;如果您在64位操作系统上运行C#代码,则在64位版本的CLR中读写64位双倍和长整数也保证是原子的。C#语言并不保证这一点,但运行时规范保证了这一点。
MSDN怎么说
以下数据类型的读和写都是原子的: bool、char、字节、s字节、short、ushort、uint、int、float和reference类型。此外,前面列表中具有基础类型的枚举类型的读和写也是原子的。其他类型的读和写,包括long、ulong、double和十进制,以及用户定义的类型,都不能保证是原子的。除了为此目的设计的库函数之外,没有任何原子读-修改-写入的保证,例如在增量或减少的情况下。
一个非常详细的答案,除了埃里克自己,可以看到here。
发布于 2013-08-23 06:54:43
我严重怀疑整个术语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加载的,然后在IL_000D处对int进行装箱,最后将装箱值存储在IL_0012。
这些指令的每个独立部分可能是原子的,但这并不意味着构成table[3] = 10;的指令链是原子的。
https://stackoverflow.com/questions/18396303
复制相似问题