"锁定"指令在x86汇编中意味着什么?

gem*_*eld 59 c++ x86 assembly qt

我在Qt的源代码中看到了一些x86程序集:

q_atomic_increment:
    movl 4(%esp), %ecx
    lock 
    incl (%ecx)
    mov $0,%eax
    setne %al
    ret

    .align 4,0x90
    .type q_atomic_increment,@function
    .size   q_atomic_increment,.-q_atomic_increment
Run Code Online (Sandbox Code Playgroud)
  1. 从谷歌搜索,我知道lock指令将导致CPU锁定总线,但我不知道CPU何时释放总线?

  2. 关于以上整个代码,我不明白这段代码是如何实现的Add

Ant*_*ams 88

  1. LOCK它本身不是指令:它是一个指令前缀,适用于以下指令.该指令必须的东西做对内存读-修改-写(INC,XCHG,CMPXCHG等)---在这种情况下它是incl (%ecx)哪个指令increments的l在举行的地址翁字ecx寄存器.

    LOCK前缀可确保CPU具有操作的持续时间适当的高速缓存线的独占所有权,并提供某些额外订购的保证.这可以通过断言总线锁来实现,但CPU会尽可能避免这种情况.如果总线被锁定,那么它仅在锁定指令的持续时间内.

  2. 此代码将要从堆栈递增的变量的地址复制到ecx寄存器中,然后lock incl (%ecx)将该变量原子递增1.接下来的两个指令将eax寄存器(保存函数的返回值)设置为0(如果变量的新值为0,否则为1.操作是增量,而不是添加(因此名称).

  • @gemfield:不,`MOV`将所有`EAX`设置为零.`SETNE`只改变低字节.没有`MOV`,`EAX`的3个高字节将包含先前操作的随机剩余值,因此返回值将是不正确的. (4认同)
  • @bruziuz:现代CPU的效率更高*:如果`lock`ed指令的数据没有越过缓存行,CPU内核可以在内部锁定该缓存行,而不是阻止所有其他的加载/存储核心.另请参阅我的回答[可以将num ++作为'int num'原子?](/sf/ask/2757569531/)了解更多详情使用MESI缓存一致性协议使可能的观察者看起来**原子*. (3认同)
  • 在一本俄罗斯书《Assembler for DOS, Windows и Linux, 2000. Sergei Zukkov》中,作者提到了关于这个前缀的以下内容:“在命令的所有时间内,提供这样的前缀,数据总线将被暂停,如果系统有不同的处理器,则在带有前缀 LOCK 的命令结束之前不能访问内存。XCHG 命令总是自动使用内存访问锁执行,即使未指定 LOCK 前缀。可以使用此前缀仅适用于命令 ADD、ADC、AND、BTC、BTR、BTS、CMPXCHG、DEC、INC、NEG、NOT、OR、SBB、SUB、XOR、XADD 和 XCHG。” (2认同)

Dan*_*Dan 12

您可能无法理解的是,增加值所需的微代码要求我们首先读取旧值.

Lock关键字强制实际发生的多个微指令看起来以原子方式运行.

如果你有两个线程试图递增相同的变量,并且它们都同时读取相同的原始值,那么它们都会增加到相同的值,并且它们都写出相同的值.

而不是让变量递增两次,这是典型的期望,你最终会增加一次变量.

lock关键字可以防止这种情况发生.


Nec*_*lis 10

从谷歌,我知道锁定指令会导致cpu锁定总线,但我不知道什么时候cpu释放总线?

LOCK是一个指令前缀,因此它只适用于下面的指令,这里的源不是很明确,但真正的指令是LOCK INC.因此总线锁定增量,然后解锁

关于以上整个代码,我不明白这些代码如何实现Add?

如果旧值为0,则它​​们不实现Add,它们实现增量以及返回指示.将使用添加LOCK XADD(但是,InterlockedIncrement/Decrement也可以实现LOCK XADD).