Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 用XCGH指令实现向下和向上(信号量)_Assembly_Semaphore - Fatal编程技术网

Assembly 用XCGH指令实现向下和向上(信号量)

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

锁定互斥锁的函数可以使用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

有没有办法用汇编语言用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