由 kernel32.dll 实现的 InterlockedExchange 在文档中有那么一句话:
This function is atomic with respect to calls to other interlocked functions.
具体实现如下:
WDK 的文档中对于 InterlockedExchange 有那么一句话:
A call to InterlockedExchange routine is atomic only with respect to other InterlockedXxx calls.
ntoskrnl.exe 中 InterlockedExchange 的实现如下:
关于 lock 前缀指令, Intel 手册里是那么说的:
Causes the processor’s LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal ensures that the processor has exclusive use of any shared memory while the signal is asserted.
The XCHG instruction always asserts the LOCK# signal regardless of the presence or absence of the LOCK prefix.
All threads and processes accessing the locked memory must ‘play fair’. This means that any one accessing the memory without trying to lock the address will not be protected by other processes locking the same address. For example:
Thread 1: lock inc ptr [edx]
Thread 2: inc ptr [edx]
If the two threads run simultaneously, thread 2 does not assert LOCK#. This means that it doesn’t check if the memory pointed by edx is locked. This means the lock is useless in this matter.
照这样说就变得跟其他一些同步方式一样了, 光自己用别人不用的话也没效果.
那么这个说法到底对吗?
主要是看到了 WDK 文档里关于 InterlockedExchange 的描述中那个 only 让我觉得似乎是在佐证这个说法.
但是,在多CPU结构中就不同了,由于系统中有多个CPU在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。我们以decl (递减指令)为例,这是一个典型的"读-改-写"过程,涉及两次内存访问。设想在不同CPU运行的两个进程都在递减某个内存单元的数值2,可能发生的情况是:
1. CPU A从内存单元把当前数值2装载进它的寄存器中;
2. CPU B从内存单元把当前数值2装载进它的寄存器中。
3. CPU A在它的寄存器中将计数值递减为1;
4. CPU B在它的寄存器中将计数值递减为1;
5. CPU A把修改后的计数值1写回内存单元。
6. CPU B把修改后的计数值1写回内存单元。
我们看到,内存里的计数值应该是0,然而它却是1。
All threads and processes accessing the locked memory must ‘play fair’. This means that any one accessing the memory without trying to lock the address will not be protected by other processes locking the same address. For example:
Thread 1: lock inc ptr [edx]
Thread 2: inc ptr [edx]
If the two threads run simultaneously, thread 2 does not assert LOCK#. This means that it doesn’t check if the memory pointed by edx is locked. This means the lock is useless in this matter.
o, 前面解释的可能不太全面和准确,其实这个问题一般的人都不大关注,看来LZ是个非常认真的人。应当这样:
如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而“把总线锁住“,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。
这里所说的是“把总线锁住”是相对于其他有lock前缀的指令,而其他普通指令还是可以照常运行的,否则系统不是要为一条指令整个都停下来。也就是说lock前缀有两个功能:1、拉低#HLOCK信号,2、在拉低之前要检查#HLOCK信号,在低的时候要等待,搞的时候才可执行。