使用XCGH指令实现Down和Up(信号量)

时间:2017-05-06 18:00:50

标签: assembly semaphore

锁定互斥锁的功能可以用汇编语言用XCHG指令编写,如下所示:

mutex_lock:
    MOVE REGISTRO,#1    
    XCHG REGISTRO,MUTEX  
    CMP REGISTRO,#0     
    JZE ok          
    CALL thread_yield   
    JMP mutex_lock      
ok: RET          

mutex_unlock:
    MOVE MUTEX,#0       
    RET

¿有没有办法用汇编语言将函数写入Up,并使用XCHG指令将函数写入Down信号量?

1 个答案:

答案 0 :(得分:1)

我的建议是使用LOCK指令。该指令基本上在单个操作中组合比较和交换。它将源操作数与目标操作数进行比较,并相应地设置标志。然后,如果它们相等(ZF == 1),则将值从源复制到目标。否则(ZF == 0),它会单独离开目的地。结合CMPXCHG前缀,这对于多线程环境中的原子操作很方便,因为它允许您安全地更新存储在共享内存中的值。

; This function attempts to obtain the semaphore. ; ; It compares the current value of the semaphore to 0. If it is 0, that means ; the semaphore is not currently locked (i.e., it is available), so this function ; sets it to 1, thus marking it as locked. Otherwise, if the semaphore is already locked, ; this function blocks (waits indefinitely) until it becomes available, ; and then locks it as described above. ; ; The address of the semaphore flag to lock is passed on the stack. ; It is the caller's responsibility to clean the stack (__cdecl). ; ; Clobbers: EAX, EDX Lock PROC mov edx, DWORD PTR [esp + 4] ; get address of semaphore (passed as sole parameter on stack) WaitUntilAvailable: mov eax, 1 lock cmpxchg DWORD PTR [edx], eax jz Finished ; TODO: Add code to suspend the thread (yield execution) while waiting, ; for example by calling the Win32 Sleep function. ; Currently, this just spins a busy loop. jmp WaitUntilAvailable Finished: ret Lock ENDP ; This function releases the semaphore. ; ; If the semaphore is currently locked (has a value of 1), it is reset to 0. ; ; The address of the semaphore flag to lock is passed on the stack. ; It is the caller's responsibility to clean the stack (__cdecl). ; ; Clobbers: EAX, EDX Unlock PROC mov edx, DWORD PTR [esp + 4] xor eax, eax lock cmpxchg DWORD PTR [edx], eax ret Unlock ENDP 的唯一警告是它需要Pentium或更高版本的处理器。今天,这显然不是问题,但如果你正在进行复古编程,你可能需要寻找其他地方。 (当然,复古程序员不必担心多个处理器,通常甚至没有多个线程。)

以下是二进制信号量的示例实现,以伪MASM样式语法编写。二进制信号量是一个值为0(解锁)或1(锁定)的信号量。

XADD

如果您愿意,可以轻松修改这些以用于计数信号量。在这种情况下,由于您希望实际递增/递减该值,因此可以使用CMPXCHG指令。我知道486及更高版本支持这一事实,而且它比; Waits for a semaphore to become available. ; ; If the value of the semaphore variable is non-zero, decrement it by 1 and return. ; Otherwise, block execution until the semaphore's value is greater than ; or equal to 1 (i.e., add the caller to the semaphore's queue and wait ; until it becomes available). ; ; Clobbers: EAX, EDX SemaphoreWait PROC mov edx, DWORD PTR [esp + 4] jmp Check WaitUntilAvailable: pause ; (or some other way to yield) Check: mov eax, DWORD PTR [edx] test eax, eax jle Check mov eax, -1 lock xadd DWORD PTR [edx], eax test eax, eax jg Finished lock inc DWORD PTR [edx] jmp WaitUntilAvailable Finished: ret SemaphoreWait ENDP ; Signals (releases) a semaphore, incrementing its value by 1. ; ; Clobbers: EAX SemaphoreSignal PROC mov eax, DWORD PTR [esp + 4] lock inc DWORD PTR [eax] ret SemaphoreSignal ENDP 快得多。这是代码可能的样子草图:

{{1}}