2

アトミック操作が無条件スワップのみであるCPUの(アセンブリ)コードを記述していると仮定します。LL/ SC、コンペアアンドスワップ、プレーンスワップはありません。(ARM9はそのような獣の例です。)スワップ操作を使用してアトミックインクリメント/デクリメント操作を実行する方法はありますか?

比較的簡単な答えがあります。それは、スワップを使用してスピンロックを構築し、それを使用して通常のインクリメントとデクリメントの周りのクリティカルセクションを提供することです。しかし、それは不格好に思えます。CASまたはLL / SCが利用可能な場合は、ロックなしで実行できることを私は知っています。だから私が本当に疑問に思っているのは、ロックを使わずにそれを行う方法があるかどうかです。

4

2 に答える 2

3

続行が許可されているかどうかを検出するためにスワップと比較の両方が必要なため、別の方法は考えられません。compare-and-swap コマンドがない場合は、次のようなループ スワップと比較を使用して実装する必要があります。

; Emulate atomic add/sub with atomic swap.
; On entry:
;   r0 contains address of variable
;   r1 contains value to add or subtract.

mutex:    defw    0           ; mutual exclusion semaphore (0=free, 1=busy).

chng:     push    r2          ; save variables.
          ld      r2,1        ; claiming value.
spin:     swap    r2,(mutex)  ; atomic swap (sounds like a good name for a band).
          bnz     spin        ; loop until you have it.
          add     (r0),r1     ; emulated atomic change.
          swap    r2,(mutex)  ; free mutex for everyone else.
          pop     r2          ; restore registers.
          ret

コードの多くの場所でそれを行っている場合にのみ、本当に不格好です。「不格好な」コードを (上記のように) 関数に分離すると、多くのコード セグメントがはるかに単純なように見えるため、非常に不格好になることがよくあります。

myvar:    defw    0
          : : : : :
          ld      r0,myvar
          ld      r1,1        ; increment
          call    chng

または、コードをさらに単純にしたい場合は、別のincranddecr関数を提供します。

; Emulate atomic incr/decr with emulated atomic change.
; On entry:
;   r0 contains address of variable

incr:     push    r1          ; save registers.
          ld      r1,1        ; increment.
          call    chng        ; do it.
          pop     r1          ; restore registers.
          ret
decr:     push    r1          ; save registers.
          ld      r1,-1       ; decrement.
          call    chng        ; do it.
          pop     r1          ; restore registers.
          ret

次に、コード シーケンスは次のようになります。

          ld      r0,myvar
          call    incr

または、マクロを実行できる場合は、さらに簡単です。

atincr:   defm                ; do this once to define macro
          ld      r0,&1
          call    incr
          endm

          atincr  myvar       ; do this in your code, as much as you like.
于 2009-11-11T03:59:10.337 に答える
0

CPU がシングル コアの場合、スワップせずにこの方法を使用できますが、注意が必要です。簡単なケースは次のとおりです。

//incrementing of variable
cli        //disable interrupts if we aren't on high priviliegied code execution level
//perform non atomic increment of variable
sti        //enable interrupts if we aren't on high priviliegied code execution level

//reading variable
cli        //disable interrupts if we aren't on high priviliegied code execution level
//perform non atomic read operation
sti        //enable interrupts if we aren't on high priviliegied code execution level

この方法はロックのように機能しますが、はるかにスマートで高速です。この方法の唯一の弱点は CPU 割り込み遅延の可能性ですが、割り込みが無効になっている内部のコードがこの遅延よりも短くて速い場合、通常は重要ではありません。

于 2009-11-11T19:09:27.887 に答える