在x86程序集中,“锁”指令是什么意思?

时间:2022-08-09 02:55:16

I saw some x86 assembly in Qt's source:

我在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
  1. From Googling, I knew lock instruction will cause CPU to lock the bus, but I don't know when CPU frees the bus?

    通过google,我知道锁指令会导致CPU锁定总线,但是我不知道CPU什么时候释放总线?

  2. About the whole above code, I don't understand how this code implements the Add?

    关于上面的全部代码,我不明白这段代码是如何实现Add的?

3 个解决方案

#1


67  

  1. LOCK is not an instruction itself: it is an instruction prefix, which applies to the following instruction. That instruction must be something that does a read-modify-write on memory (INC, XCHG, CMPXCHG etc.) --- in this case it is the incl (%ecx) instruction which increments the long word at the address held in the ecx register.

    锁不是一个指令本身:它是一个指令前缀,它适用于下面的指令。该指令必须是在内存(INC、XCHG、CMPXCHG等)上执行读-修改-写操作的指令——在本例中,是incl (%ecx)指令,该指令在ecx寄存器中保存的地址中递增长字。

    The LOCK prefix ensures that the CPU has exclusive ownership of the appropriate cache line for the duration of the operation, and provides certain additional ordering guarantees. This may be achieved by asserting a bus lock, but the CPU will avoid this where possible. If the bus is locked then it is only for the duration of the locked instruction.

    锁前缀确保CPU在操作期间对适当的缓存行拥有独占所有权,并提供某些额外的排序保证。这可以通过断言总线锁来实现,但是CPU会在可能的情况下避免这一点。如果总线被锁定,那么它只是在锁定指令的持续时间。

  2. This code copies the address of the variable to be incremented off the stack into the ecx register, then it does lock incl (%ecx) to atomically increment that variable by 1. The next two instructions set the eax register (which holds the return value from the function) to 0 if the new value of the variable is 0, and 1 otherwise. The operation is an increment, not an add (hence the name).

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

#2


11  

What you may be failing to understand is that the microcode required to increment a value requires that we read in the old value first.

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

The Lock keyword forces the multiple micro instructions that are actually occuring to appear to operate atomically.

Lock关键字强制出现的多个微指令以原子方式运行。

If you had 2 threads each trying to increment the same variable, and they both read the same original value at the same time then they both increment to the same value, and they both write out the same value.

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

Instead of having the variable incremented twice, which is the typical expectation, you end up incrementing the variable once.

不是让变量增加两次,这是典型的期望,而是让变量增加一次。

The lock keyword prevents this from happening.

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

#3


10  

From google, I knew lock instruction will cause cpu lock the bus,but I don't know when cpu free the bus ?

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

LOCK is an instruction prefix, hence it only applies to the following instruction, the source doesn't make it very clear here but the real instruction is LOCK INC. So the Bus is locked for the increment, then unlocked

锁是一个指令前缀,因此它只适用于下面的指令,这里的源代码并没有很清楚,但是真正的指令是LOCK INC.,所以总线被锁定为增量,然后解锁

About the whole above code, I don't understand how these code implemented the Add?

关于上面的全部代码,我不明白这些代码是如何实现Add的?

They don't implement an Add, they implement an increment, along with a return indication if the old value was 0. An addition would use LOCK XADD (however, windows InterlockedIncrement/Decrement are also implement with LOCK XADD).

它们不实现Add,而是实现一个增量,如果旧值为0,还会返回一个指示。另外还可以使用LOCK XADD(不过,windows InterlockedIncrement/ dec量也可以使用LOCK XADD实现)。

#1


67  

  1. LOCK is not an instruction itself: it is an instruction prefix, which applies to the following instruction. That instruction must be something that does a read-modify-write on memory (INC, XCHG, CMPXCHG etc.) --- in this case it is the incl (%ecx) instruction which increments the long word at the address held in the ecx register.

    锁不是一个指令本身:它是一个指令前缀,它适用于下面的指令。该指令必须是在内存(INC、XCHG、CMPXCHG等)上执行读-修改-写操作的指令——在本例中,是incl (%ecx)指令,该指令在ecx寄存器中保存的地址中递增长字。

    The LOCK prefix ensures that the CPU has exclusive ownership of the appropriate cache line for the duration of the operation, and provides certain additional ordering guarantees. This may be achieved by asserting a bus lock, but the CPU will avoid this where possible. If the bus is locked then it is only for the duration of the locked instruction.

    锁前缀确保CPU在操作期间对适当的缓存行拥有独占所有权,并提供某些额外的排序保证。这可以通过断言总线锁来实现,但是CPU会在可能的情况下避免这一点。如果总线被锁定,那么它只是在锁定指令的持续时间。

  2. This code copies the address of the variable to be incremented off the stack into the ecx register, then it does lock incl (%ecx) to atomically increment that variable by 1. The next two instructions set the eax register (which holds the return value from the function) to 0 if the new value of the variable is 0, and 1 otherwise. The operation is an increment, not an add (hence the name).

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

#2


11  

What you may be failing to understand is that the microcode required to increment a value requires that we read in the old value first.

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

The Lock keyword forces the multiple micro instructions that are actually occuring to appear to operate atomically.

Lock关键字强制出现的多个微指令以原子方式运行。

If you had 2 threads each trying to increment the same variable, and they both read the same original value at the same time then they both increment to the same value, and they both write out the same value.

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

Instead of having the variable incremented twice, which is the typical expectation, you end up incrementing the variable once.

不是让变量增加两次,这是典型的期望,而是让变量增加一次。

The lock keyword prevents this from happening.

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

#3


10  

From google, I knew lock instruction will cause cpu lock the bus,but I don't know when cpu free the bus ?

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

LOCK is an instruction prefix, hence it only applies to the following instruction, the source doesn't make it very clear here but the real instruction is LOCK INC. So the Bus is locked for the increment, then unlocked

锁是一个指令前缀,因此它只适用于下面的指令,这里的源代码并没有很清楚,但是真正的指令是LOCK INC.,所以总线被锁定为增量,然后解锁

About the whole above code, I don't understand how these code implemented the Add?

关于上面的全部代码,我不明白这些代码是如何实现Add的?

They don't implement an Add, they implement an increment, along with a return indication if the old value was 0. An addition would use LOCK XADD (however, windows InterlockedIncrement/Decrement are also implement with LOCK XADD).

它们不实现Add,而是实现一个增量,如果旧值为0,还会返回一个指示。另外还可以使用LOCK XADD(不过,windows InterlockedIncrement/ dec量也可以使用LOCK XADD实现)。