atomique swap avec SAE (avec gcc synchroniser les builtins)
Pouvez le compare-and-swap fonction être utilisé pour échanger des variables atomiquement?
Je suis à l'aide de C/C++ via gcc sur x86_64 RedHat Linux, plus précisément l' __synchroniser les builtins.
Exemple:
int x = 0, y = 1;
y = __sync_val_compare_and_swap(&x, x, y);
Je pense que cela se résume à savoir si x peut changer entre &x et x; par exemple, si &x constitue une opération, il pourrait être possible pour x pour changer entre &x et x dans les arguments. Je veux supposer que la comparaison implicite ci-dessus sera toujours vrai; ma question est de savoir si je peux. Évidemment il y a le bool version de CAS, mais je ne peux pas obtenir le vieux x pour écrire dans y.
Un exemple plus utile peut-être d'insérer ou de retirer de la tête d'une liste chaînée (gcc demandes de soutien de type pointeur, donc suppose que c'est ce que l'elem et la tête sont):
elem->next = __sync_val_compare_and_swap(&head, head, elem); //always inserts?
elem = __sync_val_compare_and_swap(&head, head, elem->next); //always removes?
De référence:
http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html
OriginalL'auteur limalave | 2010-06-04
Vous devez vous connecter pour publier un commentaire.
L'opération risque de ne pas enregistrer la nouvelle valeur dans la destination en raison d'une course avec un autre thread que des changements à la valeur, au même moment où vous essayez de. Le CAS primitive ne garantit pas que l'écriture se produit uniquement que l'écriture se produit si la valeur est déjà ce que l'on attend. Le primitif ne peut pas savoir ce que le comportement correct est si la valeur n'est pas ce qui est prévu, rien ne se passe dans ce cas, vous devez corriger le problème en vérifiant la valeur de retour voir si l'opération a fonctionné.
Donc, votre exemple:
ne sont pas nécessairement insérer le nouvel élément. Si un autre thread insère un élément dans le même moment, il y a une condition de concurrence qui pourrait causer ce thread appel à
__sync_val_compare_and_swap()
ne pas mettre à jourhead
(mais ni ce thread ou l'autre thread de l'élément est encore perdu si vous la manipulez correctement).Mais, il y a un autre problème avec cette ligne de code (même si
head
obtenir la mise à jour, il y a un bref instant dans le temps oùhead
points de l'élément inséré, mais que l'élémentnext
pointeur n'a pas été mis à jour pour pointer à la précédente à la tête de la liste. Si un autre thread fonce dans le moment et tente de marcher sur la liste, les mauvaises choses se produisent.Correctement mise à jour de la liste de changement de la ligne de code à quelque chose comme:
Ou utiliser le
bool
variante, qui je pense est un peu plus pratique:C'est un peu moche, et j'espère que j'ai bien compris (il est facile de trébucher dans les détails de thread-safe code). Il doit être enveloppé dans un
insert_element()
fonction (ou mieux encore, utiliser une bibliothèque appropriée).Aborder l'ABA problème:
Je ne pense pas que l'ABA problème est pertinente pour le présent "ajouter un élément à la tête d'une liste" du code. Disons qu'un thread veut ajouter un objet
X
à la liste et lorsqu'il exécuteelem->next = head
,head
a de la valeurA1
.Puis avant l'
__sync_val_compare_and_swap()
est exécuté, un autre ensemble de threads arrive et:A1
de la liste, en faisanthead
point deB
A1
et la libèreA2
qui arrive à être à la même adresse queA1
étaitA2
à la liste, de sorte quehead
maintenant les points àA2
Depuis
A1
etA2
ont le même identifiant/adresse, c'est une instance de l'ABA problème.Cependant, il n'a pas d'importance dans ce cas puisque le thread de l'ajout de l'objet
X
ne se soucie pas que lahead
points à un autre objet qu'il a commencé avec tous il se soucie est que lorsqueX
est mis en file d'attente:X
ont été ajoutés à la liste (par ce fil)pourriez-vous élaborer sur la façon dont vous allez à propos de la fixation? Ou voulez-vous tout simplement utiliser l'une des méthodes suggérées dans l'article de wikipedia sur l'ABA problème?
Je ne suis pas sûr que l'ABA problème est un problème ici que j'ai mis à jour la réponse à indiquer pourquoi. Si je ne me trompe, je vous en serais reconnaissant de détails.
OriginalL'auteur Michael Burr
Nope. Le CAS des instructions sur x86 prend une valeur dans un registre, et les compare/écrit contre une valeur en mémoire.
Pour atomiquement permuter deux variables, il faudrait travailler avec les deux opérandes mémoire.
Quant à savoir si
x
peut changer entre&x
etx
? Oui, bien sûr on peut.Même sans le
&
, il pourrait changer.Même dans une fonction telle que
Foo(x, x)
, vous pourriez obtenir deux valeurs différentes de x, puisque pour appeler la fonction, le compilateur doit:entre ces deux opérations, un autre thread pourrait facilement modifier la valeur de
x
.OriginalL'auteur jalf
Il semble que vous êtes à la recherche pour le contrefil-échange primitif, pas le contrefil-comparer-échange. Qui sera inconditionnellement atomiquement swap de la tenue de s'inscrire auprès de la cible emplacement de mémoire.
Toutefois, vous avez toujours un problème avec les conditions de concurrence entre les missions de
y
. Parfoisy
est un local, dans ce cas, ce sera en sécurité, mais si les deuxx
ety
sont partagés vous avez un problème majeur et aura besoin d'une serrure pour le résoudre.OriginalL'auteur Ben Voigt