代码之家  ›  专栏  ›  技术社区  ›  vava

一条汇编指令总是以原子方式执行吗?[副本]

  •  15
  • vava  · 技术社区  · 16 年前

    今天我遇到了这个问题:

    你有密码

    static int counter = 0;
    void worker() {
        for (int i = 1; i <= 10; i++)
            counter++;
    }
    

    如果 worker counter 在两者都完成之后?

    我知道实际上它可以是任何东西。但我的内心告诉我 counter++ 计数器 将是20。

    11 回复  |  直到 16 年前
        1
  •  20
  •   Nathan Fellman    16 年前

    counter++

    inc counter
    

    这转化为以下微观操作:

    • 负载 counter 到CPU上的隐藏寄存器
    • 计数器

    mov eax, counter
    inc eax
    mov counter, eax
    

    请注意,如果其他代理更新 计数器 计数器 在商店之后。此代理可以是同一核心中的另一个线程、同一CPU中的另一端、同一系统中的另一侧CPU,甚至是使用DMA(直接内存访问)的某个外部代理。

    如果你想保证这一点 inc lock

    lock inc counter
    

    计数器 在货物和商店之间。


    对于更复杂的指令,除非它们支持 前缀。

        2
  •  9
  •   Yuval Adam    16 年前

    -你可以 假设您使用的程序语言是将一行看似简单的代码编译成一条汇编指令。此外,在某些架构上,您不能假设一个机器代码会原子地执行。

        3
  •  8
  •   Juergen    16 年前

    在过去的好日子里,它是。但今天,随着复杂的CPU、长时间运行的指令、超线程。..事实并非如此。一些CPU保证 一些 递增/递减指令是原子指令。原因是,它们非常适合非常简单的同步。

    编辑:

        4
  •  6
  •   Darin Dimitrov    16 年前
    1. 在具有超线程技术的处理器或多处理器系统上,不能保证增量/减量操作以原子方式执行。
        5
  •  4
  •   jop    16 年前

    如果我没记错我的英特尔x86汇编程序,INC指令只适用于寄存器,不直接适用于内存位置。

    因此,计数器++不会是汇编程序中的单个指令(只是忽略后增量部分)。它至少有三条指令:将计数器变量加载到寄存器、递增寄存器、将寄存器加载回计数器。这仅适用于x86架构。

        6
  •  3
  •   Artur Soler    16 年前

        7
  •  3
  •   Artem Barger    16 年前


    此外,竞争条件问题与记忆模型(连贯性、顺序性、释放连贯性等)密切相关,对于每种模型,答案和结果可能不同。

        8
  •  2
  •   user541686    13 年前

    在大多数情况下, 。事实上,在x86上,您可以执行指令

    push [address]
    

    *stack-- = *address;
    

    .

    内存传输也不可能在一个周期内完成!

        9
  •  1
  •   peSHIr    16 年前

    这可能不是你问题的实际答案,但(假设这是C#或其他.NET语言)如果你愿意的话 counter++ 要真正成为多线程原子,您可以使用 System.Threading.Interlocked.Increment(counter) .

    请参阅其他答案,了解许多不同的原因/方式的实际信息 计数器++ 不可能是原子的。 ;-)

        10
  •  -1
  •   Marco van de Voort    16 年前

    在许多其他处理器上,存储系统和处理器之间的分离更大。(通常这些处理器可以是小字节序或大端序,具体取决于内存系统,如ARM和PowerPC),如果内存系统可以重新排序读取和写入,这也会对原子行为产生影响。

    http://en.wikipedia.org/wiki/Memory_barrier )

    因此,简而言之,虽然原子指令在intel上就足够了(具有相关的锁前缀),但在非intel上必须做更多的工作,因为内存I/O的顺序可能不同。

    当将“无锁”解决方案从英特尔移植到其他架构时,这是一个已知的问题。

        11
  •  -3
  •   ChrisBD    16 年前