__synchronisation_val_comparez_et_swap vs __synchronisation_bool_comparez_et_swap
J'ai été à la réflexion sur les valeurs de retour de ces deux fonctions. L' __synchronisation_bool_comparez_et_swap fonction de la valeur de retour semble avoir des avantages évidents, c'est à dire que je peux l'utiliser pour savoir si le swap opération a eu lieu. Cependant je ne peux pas voir d'un bon usage de __synchronisation_val_comparez_et_swaps valeur de retour.
Tout d'abord, permet d'avoir une signature de fonction de référence (à partir de GCC docs moins le var args):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
Le problème que je vois est que la valeur de retour __synchronisation_val_comparez_et_swap est l'ancienne valeur de l' *ptr. Pour être précis, c'est la valeur qui a été vu par la mise en œuvre de cette fonction une fois les barrières de la mémoire avait été mis en place. Je mentionner explicitement pour répondre au fait que, entre l'appel __synchronisation_val_comparez_et_de swap et de l'exécution des instructions pour appliquer la barrière de la mémoire de la valeur de *ptr pourrait facilement changer.
Maintenant, lorsque la fonction renvoie ce que je peux faire avec cette valeur de retour? Il n'y a pas de point d'essayer de le comparer à *ptr, car *ptr peut maintenant être changé sur d'autres threads. De même, la comparaison de newval et *ptr n'a pas vraiment m'aider non plus (sauf si je lock *ptr qui a probablement sape mon utilisation de atomics en premier lieu).
Donc tout ce qui est vraiment me reste à faire est de demander si la valeur de retour == oldval, qui est effectivement (voir ci-dessous pour une mise en garde) en se demandant si le swap opération a eu lieu. Si je pouvais avoir juste utilisé __synchronisation_bool_comparez_et_swap.
La mise en garde que je viens de mentionner, c'est que la seule différence que je peux voir ici, est que cela ne me dites pas si le swap est survenue ou non, il m'a juste dit qu'à un certain moment avant de la barrière de la mémoire a été publié *ptr avait la même valeur que newval. Je suis en train d'étudier la possibilité que oldval == newval (bien que j'avais du mal a voir un moyen de mise en œuvre de la fonction de manière efficace afin qu'il puisse vérifier ces valeurs et pas de swap si elles étaient les mêmes, donc c'est probablement un point discutable). Cependant je ne peux pas voir une situation où le savoir cette différence serait de faire une différence pour moi sur le site d'appel. En fait, je ne peux pas imaginer une situation où je mettrais oldval et newval être égaux.
Ma question est donc:
Est-il un cas d'utilisation dans lesquels l'aide d' __synchronisation_val_comparez_et_swap et __ _ _ synchronisation_bool_comparez_et_swap ne serait pas d'équivalent, c'est à dire il y a une situation où l'on fournit plus d'informations que les autres?
De CÔTÉ
La raison pour laquelle je pensais c'était que j'ai trouvé une mise en œuvre de l' __synchronisation_val_comparez_et_swap en termes de sync_bool_compare_and_swap qui a une course:
inline int32_t __sync_val_compare_and_swap(volatile int32_t* ptr, int32_t oldval, int32_t newval)
{
int32_t ret = *ptr;
(void)__sync_bool_compare_and_swap(ptr, oldval, newval);
return ret;
}
La course sur le stockage de l' *ptr en ret, *ptr pourrait changer avant d' __synchronisation_bool_comparez_et_swap est appelé. Cela m'a fait réaliser que je ne semble pas être un moyen sûr (sans obstacles ou des serrures) de la mise en œuvre __synchronisation_val_comparez_et_swap en termes de sync_bool_compare_and_swap. Cela m'a fait penser que l'ancien doit fournir plus de "l'information" que la seconde, mais que par ma question je ne vois pas qu'il fait vraiment.
Vous avez raison que le code dans votre "côté" est buggy/a un sérieux condition de course. Une nouvelle tentative de la boucle est nécessaire pour le rendre correct. Voir ma réponse.
OriginalL'auteur Andrew Parker | 2015-04-28
Vous devez vous connecter pour publier un commentaire.
L'opération fourni par
__sync_val_compare_and_swap
peut toujours être mise en œuvre en termes de__sync_bool_compare_and_swap
(et bien sûr, l'autre sens est évidemment possible), donc en termes de puissance les deux sont équivalents. Cependant la mise en œuvre de__sync_val_compare_and_swap
en termes de__sync_bool_compare_and_swap
n'est pas très efficace. Il ressemble à quelque chose comme:Le travail supplémentaire est nécessaire parce que vous pourriez observer l'échec de
__sync_bool_compare_and_swap
mais a ensuite lu une nouvelle valeur à partir de*ptr
qui correspond àoldval
.Comme pour pourquoi vous pourriez préférer le
__sync_val_compare_and_swap
comportement, la valeur qui a causé l'échec peut vous donner un point de départ pour recommencer l'opération de manière plus efficace ou peut indiquer un sens cause de l'échec pour une opération qui ne sera pas rejugé". Comme un exemple, voir le code pourpthread_spin_trylock
dans musl de la libc (dont je suis l'auteur):http://git.musl-libc.org/cgit/musl/tree/src/thread/pthread_spin_trylock.c?id=afbcac6826988d12d9a874359cab735049c17500
Il
a_cas
est équivalent à__sync_val_compare_and_swap
. D'une certaine façon c'est un exemple stupide car il vient de sauver une branche conditionnelle ou se déplacer en utilisant l'ancienne valeur, mais il existe d'autres situations où plusieurs valeurs sont possibles et de connaître celui qui a provoqué l'échec de l'opération de questions.Parce que pour fournir un travail de mise en œuvre de
__sync_val_compare_and_swap
, vous retourner une valeur à pointe-à objet avait à un certain moment au cours de l'opération qui n'est pas égal à l'argumentoldval
. La recherche d'une telle valeur est impossible sans la boucle jusqu'à ce que vous recherchez. Imaginez un autre threads rapidement basculement (via valide atomique swaps) de l'objet de valeur entreoldval
et quelques autres-valeur cachée.Je vois. Une dernière chose me trouble. *ptr pourrait changer avant de pouvoir le comparer avec oldval, mais ça pourrait changer à une autre valeur qui n'est pas égal à oldval. Ainsi, cette mise en œuvre pourrait renvoyer une valeur qui n'ont aucun rapport à pourquoi le swap a été infructueuse. C'est un pédant point, mais je me demande si c'est en contradiction avec la spécification de la fonction. Pour citer GCC pages: "Le “val” version retourne le contenu de l' *ptr avant l'opération.". Cette mise en œuvre ne serait pas de retourner le contenu de *ptr avant l'op.
Ce qui compte comme "avant l'op" est quelque chose que vous obtenez de décider si vous êtes à l'échec (et donc de ne pas changer le fait-à l'objet). Tant que vous retourner une valeur autre que
oldval
que*ptr
avait à un certain moment au cours de l'appel, et d'assurer le bon séquençage de tous les autres magasins/charges relatif à la boutique qui a causé la valeur de retour d'être observé, vous pouvez définir le moment de "l'op" comme le retour de la fonction.Si d'autre part le compare-and-swap réussit, alors le moment de l'opération est limité par sa visibilité à d'autres threads, etc. mais alors il n'a pas d'importance parce que vous êtes de retour
oldval
.OriginalL'auteur R..