2011-08-04 7 views
13

gccインラインアセンブリを使用するのが初めてで、x86マルチコアマシンでスピンロック(競合条件なし)を(AT & T構文を使用して)実装できるかどうか疑問に思っていました。cmpxchgを使用したx86スピンロック

 
spin_lock: 
mov 0 eax 
lock cmpxchg 1 [lock_addr] 
jnz spin_lock 
ret 

spin_unlock: 
lock mov 0 [lock_addr] 
ret 

答えて

21

あなたは正しい考えを持っているが、あなたのASMが壊れている:

cmpxchgは、即値オペランドとレジスタのみを動作することはできません。

lockは、movの有効な接頭辞ではありません。アライメントされたアドレスへのmovは、x86ではアトミックなので、とにかくlockは必要ありません。

spin_lock: 
xorl %ecx, %ecx 
incl %ecx 
spin_lock_retry: 
xorl %eax, %eax 
lock; cmpxchgl %ecx, (lock_addr) 
jnz spin_lock_retry 
ret 

spin_unlock: 
movl $0 (lock_addr) 
ret 

注GCCは原子ビルトインを持っているので、あなたが実際にインラインアセンブラを使用する必要はありません:

私が& T構文で使用してきましたので、いくつかの時間となっているが、私はすべてを覚えて願っていますこの達成:Boは以下の言うように

void spin_lock(int *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)); 
} 

void spin_unlock(int volatile *p) 
{ 
    asm volatile (""); // acts as a memory barrier. 
    *p = 0; 
} 

を、ロックされた命令がコストを負担:あなたが使用して一人一人が自分のキャッシュをフラッシュし、あなたが十分なCPUを持っている場合は非常に高価になることができ、システムのメモリバスをロックする必要があります。でも、多くのCPUせず、それはまだ簡単で価値がある、それは周りに最適化する:あなたはこのようにスピンコードを持っているとき

void spin_lock(int volatile *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)) 
    { 
     while(*p) _mm_pause(); 
    } 
} 

pause命令がハイパースレッディングのCPUのパフォーマンスのために不可欠である - それは、第二のスレッドが実行することができます最初のスレッドが回転しています。 pauseをサポートしないCPUでは、nopとして扱われます。

+0

無効spin_lockのパラメータは、()もvolatile宣言されるべきか? – ManRow

+1

いいえ、 '__sync_bool_compare_and_swap'はすでに' volatile'として扱います。 –

+0

'spin_unlock'の中のメモリバリアとして使用されるasmにはおそらくメモリクローバーが含まれているはずです。一方、「書き込み障壁を実行し、0を書き込む」ように設計された「__sync_lock_release」がありますが、それはまったく考える必要はなく、ややポータブルです。それは明示的に読取りの障壁として働いていません(それは実際にはターゲットアーキテクチャ上で実行されています)が、それは問題ありません。最悪の場合は、まれなケースの中で1つの特別なスピンを行う別のスレッドです。 – Damon

3

これは、メモリバス上の競合が少ないと入れます

void spin_lock(int *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)) while(*p); 
} 
+0

合意しましたが、このコードはあまり良くありません。単純なwhile(* p)は、コンパイラーが簡単に最適化することができます。いくつかの壁を追加してください。また、Intelチップに_mm_pause()を追加すると、パフォーマンスが大幅に向上します。 –

関連する問題