MSIL操作码是原子的吗?

时间:2012-01-31 19:57:00

标签: .net multithreading atomic cil

我正在玩MSIL反编译器 - ILDASM,我试图反编译一个简单的.NET方法。

操作码看起来像这样:

.method private hidebysig static int32  Add(int32 a,
                                            int32 b) cil managed
{
  // Code size       18 (0x12)
  .maxstack  2
  .locals init ([0] int32 c,
           [1] int32 d,
           [2] int32 CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.5
  IL_0003:  add
  IL_0004:  stloc.0
  IL_0005:  ldarg.1
  IL_0006:  ldc.i4.s   10
  IL_0008:  add
  IL_0009:  stloc.1
  IL_000a:  ldloc.0
  IL_000b:  ldloc.1
  IL_000c:  add
  IL_000d:  stloc.2
  IL_000e:  br.s       IL_0010
  IL_0010:  ldloc.2
  IL_0011:  ret
}

我想知道的是 - 这些操作码是原子的吗?即在抢先式调度内核中,单个操作码在完成执行之前是否有可能被抢占?这里的操作码可以很容易地以1:1的方式映射到asm指令,因为它们具有用于加载,存储,添加等的单独操作码。

但是在更复杂的操作码的情况下呢?比如“call”,当操作数是一个方法引用标记时,应首先遵循该方法来解析该方法然后调用?那是原子吗?

2 个答案:

答案 0 :(得分:14)

不,并非所有操作码都是原子的。例如,如果对大于本机指针大小的值类型使用stlocldloc,那么不能保证它是原子的。

ECMA 335的第12.6.6节保证了这么多:

  

符合要求的CLI应保证在对位置进行所有写访问时,对正确对齐的内存位置的读写访问权限不大于本机字大小(native int类型的大小)是原子的(参见§12.6.2)大小相同。原子写入除了写入之外不得改变任何位。

...但是有一个注释:

  

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

这意味着任何存储或读取Int64的操作码都不能保证在x86上是原子的,例如......

答案 1 :(得分:0)

我不认为IL指令定义了原子性。它是根据负载定义的,并存储在内存中。

关于装载和存储的原子性规则很复杂。它们与存储值的对齐和大小有关。

你的“呼叫”示例没有意义:它不访问内存。原子性的概念与调用指令无关。