您的代码等于:
static __inline__ int xchg_asm(int* lock, int val) {
int save_old_value_at_eax;
save_old_value_at_eax = *lock; /* with a wrong lock prefix */
xchg *lock with val and discard the original value of *lock.
return save_old_value_at_eax; /* but it not the real original value of *lock */
}
从代码中可以看出,save_old_value_at_eax
cpu执行xchg时是没有真正的原始值的。您应该通过 xchg 指令获取旧/原始值,而不是在执行 xchg 之前保存它。(“它不是真正的旧值/原始值”是指,如果另一个 CPU 在此 CPU 保存值之后但在此 CPU 执行 xchg 指令之前获取锁,则此 CPU 将获取错误的旧值,并认为它占用了锁成功,因此,两个CPU同时进入CS)。您已将读取-修改-写入指令分成三个指令,整个三个指令都不是原子的(即使您将锁定前缀移动到 xchg)。
我猜你认为锁定前缀会锁定全部三个指令,但实际上锁定前缀只能用于它所附加的唯一指令(并非所有指令都可以附加)而且我们不需要在 SMP 上为 xchg 锁定前缀. 引用自 linux_kernel_src/arch/x86//include/asm/cmpxchg.h
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway.
* Since this is generally used to protect other memory information, we
* use "asm volatile" and "memory" clobbers to prevent gcc from moving
* information around.
*/
我的建议:
- 不要重复自己,请使用 linux 内核的自旋锁。
- 不要重复你自己,如果你确实想实现自旋锁,请使用 linux 内核的 xchg()、cmpxchg()。
- 了解有关说明的更多信息。您还可以了解 linux 内核是如何实现它的。