Assembly 用XCGH指令实现向下和向上(信号量)
锁定互斥锁的函数可以使用XCHG指令以汇编语言编写,如下所示:Assembly 用XCGH指令实现向下和向上(信号量),assembly,semaphore,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
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
有没有办法用汇编语言用XCHG指令编写向上和向下信号量的函数 我的建议是使用
CMPXCHG
指令。此指令基本上将比较和交换结合在一个操作中。它将源操作数与目标操作数进行比较,并相应地设置标志。然后,如果它们相等(ZF==1),它将值从源复制到目标。否则(ZF==0),它只保留目标。结合锁
前缀,这对于多线程环境中的原子操作非常方便,因为它允许您安全地更新存储在共享内存中的值
CMPXCHG
唯一需要注意的是,它需要一个奔腾或更高版本的处理器。今天,这显然不是一个问题,但如果你正在做复古编程,你可能需要去别处看看。(当然,复古程序员实际上不必担心多个处理器,通常甚至没有多个线程。)
下面是一个二进制信号量的示例实现,用伪MASM风格的语法编写。二进制信号量的值为0(未锁定)或1(已锁定)
如果需要的话,您可以很容易地修改它们以用于计数信号量。在这种情况下,由于您希望实际增加/减少该值,因此可以使用XADD
指令。我知道486和更高版本支持这一点,而且它比CMPXCHG
快得多。下面是代码的草图:
; 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
当然,使用互斥来保护信号量。
; 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