【问题标题】:Are MSIL opcodes atomic?MSIL 操作码是原子的吗?
【发布时间】:2012-01-31 19:56:59
【问题描述】:

我正在使用 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 指令,因为它们具有用于加载、存储、添加等单独的操作码。

但是如果操作码更复杂怎么办?像“调用”一样,当操作数是一个方法引用标记时,应该首先遵循它来解析方法然后调用?那也是原子的吗?

【问题讨论】:

  • 取决于处理器...

标签: .net multithreading atomic cil


【解决方案1】:

不,不是所有的操作码都是原子的。例如,如果您将 stlocldloc 用于大于本机指针大小的值类型,则不能保证是原子的。

ECMA 335 的第 12.6.6 节保证了这一点:

当所有对某个位置的写访问时,符合标准的 CLI 应保证对正确对齐的内存位置的读写访问不大于本机字大小(本机 int 类型的大小)是原子的(参见第 12.6.2 节)大小相同。原子写入不应改变除已写入的位之外的任何位。

...但是有一个注释:

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

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

【讨论】:

  • 哇!这是一个令人惊讶的大开眼界。这意味着,如果您有两个线程将值存储到它们都可见的范围内的“long”类型变量中,您可能期望该值的值不等于任何存储。正确的?例如。 thread1 { val = 1 },thread2 { val = 4294967296},结果值可能是 4294967297?因为这些值涉及两个不同的 32 位集?保证这两个值中的任何一个都将被存储的唯一方法是使用 Interlocked.* ?
  • 是的。挥发性也无济于事。 (它的帮助很小)
  • @KariMA.:当然。在没有任何锁定的情况下在多个线程之间共享状态很棘手......尽量避免这样做。
  • @John,但在整数(32 位整数)的情况下,我保证全局变量中的存储值将是两者之一。如果我错了,请纠正我。
  • @KarimAgha 您可以通过alwaysboth 32 位和64 位模式下保证原子64 位获取和存储 i> 使用Interlocked.* 指令读/写受影响的内存位置。对于 32 位模式的 .NET,这是获得 64 位无锁操作所需的正确性保证的唯一方法。
【解决方案2】:

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

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

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

【讨论】:

  • 不,我在“调用”的情况下要问的是,是否有可能在被调用的方法开始执行之前抢占线程。例如在解析引用时。
猜你喜欢
  • 1970-01-01
  • 2018-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-05
  • 2015-01-10
  • 2016-11-05
相关资源
最近更新 更多