锁定互斥锁的功能可以用汇编语言用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信号量?
答案 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}}