Vous avez la bonne idée, mais votre asm est cassé:
cmpxchg
peut ne pas fonctionner avec un opérande immédiat, seuls les registres.
lock
n'est pas un préfixe valide pour mov
. mov
à une adresse alignée est atomique sur x86, de sorte que vous n'avez pas besoin de lock
de toute façon.
Il a été un certain temps depuis que je suis utilisé à & T syntaxe, l'espoir je me suis souvenu tout:
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
Notez que GCC a builtins atomique, de sorte que vous n'avez pas réellement besoin d'utiliser asm en ligne à cette fin:
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;
}
Comme Bo dit ci-dessous, les instructions verrouillées encourent un coût: tous que vous utilisez doit vider votre cache et verrouiller le bus mémoire de votre système, ce qui peut être assez cher si vous avez suffisamment de processeurs. Même sans beaucoup de processeurs, il est toujours facile et vaut la peine d'optimiser autour de:
void spin_lock(int volatile *p)
{
while(!__sync_bool_compare_and_swap(p, 0, 1))
{
while(*p) _mm_pause();
}
}
L'instruction pause
est vital pour les performances sur les processeurs HyperThreading lorsque vous avez du code qui tourne comme ça - il permet au second fil exécuter tandis que le premier fil tourne. Sur les processeurs qui ne prennent pas en charge pause
, il est traité comme nop
.
Si le paramètre pour spin_lock void() être déclaré aussi volatile? – ManRow
N ° '__sync_bool_compare_and_swap' le traite déjà comme' volatile'. –
L'asm utilisé comme barrière de mémoire à l'intérieur de 'spin_unlock' devrait probablement inclure le clobber de la mémoire. Cependant, d'un autre côté, il y a '__sync_lock_release' qui est conçu pour faire la chose" write barrier, and write 0 "sans avoir à penser à asm du tout, et il est même" quelque peu portable ". Il ne fonctionne pas explicitement en tant que barrière de lecture (il le fait _incidentially_ sur l'architecture cible), mais c'est OK. La pire chose à faire est qu'un autre thread fait un tour supplémentaire dans un cas rare et improbable. – Damon