2012-01-17 442 views
39

我看到Qt的源一些x86汇编:“锁”指令在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 
  1. 从谷歌搜索,我知道lock指令将导致CPU锁定总线,但是当CPU释放总线,我不知道吗?

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

+8

请参阅http://stackoverflow.com/a/3339380/856777 – Lucian 2012-01-17 07:37:58

+0

相关:我的答案[num num可以原子为'int num'?](https://stackoverflow.com/questions/39393850/can -num-be-atomic-for-int-num)解释了x86上的原子性,以及'lock'前缀的作用,以及没有它的情况。 – 2017-09-13 03:47:09

回答

64
  1. LOCK不是指令本身:它是一个指令前缀,它适用于下面的指令。该指令必须的东西做内存(INCXCHGCMPXCHG等)的读 - 修改 - 写---在这种情况下,它是incl (%ecx)指令,incecx寄存器中保存的地址rements的l翁词。

    LOCK前缀确保CPU在操作期间拥有适当缓存行的独占所有权,并提供某些额外的订购保证。这可以通过声明总线锁来实现,但CPU会尽可能地避免这种情况。如果总线被锁定,那么只有在锁定指令的持续时间内。

  2. 此代码复制变量的地址要在堆栈递增扎进ecx寄存器,然后它lock incl (%ecx)由1原子方式增加该变量接下来的两个指令设置eax寄存器(其保持的返回值如果变量的新值是0,则返回0,否则返回1。该操作是增量,而不是一个添加(因此名称)。

+0

因此,指令“mov $ 0,%eax”似乎是多余的? – gemfield 2012-01-18 03:23:04

+4

@gemfield:不,“MOV”将“EAX”全部设置为零。 SETNE只改变低字节。如果没有'MOV','EAX'的3个高字节将包含之前操作的随机剩余值,所以返回值不正确。 – 2012-01-18 07:34:15

+0

非常感谢 – gemfield 2012-01-19 02:26:27

10

从谷歌,我知道锁指令将导致CPU锁定总线,但我 当CPU释放总线不知道吗?

LOCK是一个指令前缀,因此它仅适用于以下指令,源不会使这里说得很清楚,但真正的指令是LOCK INC。所以总线被锁定为增量,然后解锁

关于整个上面的代码,我不明白这些代码 如何实现添加?

他们没有实现的添加,它们实现的增量,与返回指示一起,如果原来的值是0的除了会使用LOCK XADD(但是,Windows InterlockedIncrement /递减也与LOCK XADD实现)。

+0

谢谢!那么哪个寄存器存储函数的值(q_atomic_increment)的返回值? – gemfield 2012-01-17 08:18:40

+1

返回值存储在%eax中 – nos 2012-01-17 08:59:17

+0

所以,代码:“返回q_atomic_increment(_ q_value)!= 0”是检验%EAX是否不等于零? – gemfield 2012-01-17 09:15:53

10

你可能不明白的是,增加一个值所需的微码需要我们先读取旧值。

Lock关键字强制实际发生的多条微指令看起来像原子一样运行。

如果你有每个试图增加同一个变量2个线程,他们都在同一时间,然后他们俩增量读取相同的原始值相同的值,并且他们写出来的值相同。

代替具有递增两次变量,这是典型的期待,你最终一次递增变量。

锁定关键字防止这种情况的发生。