2017-07-29 3 views
4

Considérons que j'ai deux booléens atomiques comme suit. Puis-je dire que l'opération suivante est atomique? ou dois-je utiliser lock_guard pour m'assurer qu'ils sont assignés ensemble?est plusieurs affectations de variables atomiques, une opération atomique?

x = y = true; // are two bools assigned together atomically? 

également considérer dans un autre fil Je veux lire ces booléens.

if(!x && !y) ... 

mon hypothèse est que ce n'est pas atomique, peut-être son mieux d'utiliser atomic<int> à la place?

+0

question différente, mais un peu liée: https://stackoverflow.com/questions/8858387/stdatomic-treat-a-pair-of-atomic-int32-as-one-atomic-int64 – user463035818

+0

@RickAstley Je ne sais pas voyez comme cela suit. 'x.store' promet que l'action d'assigner' x' est atomique; il ne dit pas si l'évaluation de son argument est atomique avec cela. Cela n'a tout simplement aucun sens. Par votre raisonnement, vous pouvez stocker le résultat d'une fonction énorme et rendre toute la fonction atomique. Maintenant, votre variable atomique (qui pourrait être un simple booléen) agit comme un mutex. –

Répondre

4

Non, ce n'est pas le cas. Tout ce qu'une opération atomique garantit est qu'aucune opération intervenante n'intervient sur la variable. Dans votre exemple, il est tout à fait possible que y soit assigné, quelque chose d'indépendant se produit (mais seulement dans un autre thread, dans le réordonnancement actuel du thread ne se produira pas à cause de la barrière de mémoire impliquée par operator= sur un atomique), puis x . La même chose est vraie en les lisant.

Si vous voulez vraiment que ces opérations soient atomiques, vous devez utiliser un seul type atomique qui encapsule les deux informations. Il y a plusieurs façons de le faire. vous pouvez utiliser un caractère et utiliser des bits différents au prix de certaines opérations de masquage de bits, vous pouvez utiliser un entier de 16 bits, mais je vais illustrer par l'approche la plus claire (IMHO): une structure avec deux booléens.Ceci peut ou non optimiser autant que d'utiliser un entier de 16 bits et de sortir manuellement les deux booléens. gcc semble optimiser cela extrêmement bien; il transforme l'opération en une seule écriture + clôture de la mémoire, mais clang ne fait pas aussi bien: https://godbolt.org/g/moiT9Y.

+0

merci. J'ai essayé d'utiliser un entier atomique de 16 bits, mais cela compliquait la lecture. L'utilisation de struct avec des champs descriptifs et individuels est une bonne suggestion. –

2
x = y = true; // are two bools assigned together atomically? 

Cette ligne est évidemment pas une opération atomique x et y sont dans deux endroits différents dans la mémoire: il est impossible de définir deux endroits qui ne sont pas continuous³ un l'autre en même temps.

Le mot atomique implique que lecture ou d'écriture se fait dans un cycle¹ cpu, donc une variable est sûre, mais x et y sont deuxdifférentes variables atomiques.

Si vous avez des doutes sur ne pas hésiter à regarder le code binaire produit, grâce à l'utilisation d'un désassembleur.

if(!x && !y) ... 

La même: la CPU doivent accéder à la valeur des deuxdifférentes des variables en copiant les valeurs dans son propre registre, faire une évaluation booléenne, nier, et effectuer une evaluation² ; opérations clairement non atomiques.

¹ il est pas si simple, mais d'un vous devez penser que
² encore, il est pas si simple, langue plus point de developpeur de vue, comme le compilateur peut sûrement faire des optimisations, et l'unité centrale de traitement peut faire certaines choses par elles-mêmes
³ même avec des emplacements continus, la taille totale doit être lisible/inscriptible en une seule boucle: 1Mo de données ne sont clairement pas lisibles dans une boucle par le CPU, même si toutes les données sont continuellement côte à côte.

+5

Vous avez quelques fausses idées sur ce que 'std :: atomic' est. C'est une norme qui permet d'écrire du code atomique multiplateforme. La taille du registre CPU ou "une boucle" est totalement hors de propos (sauf bien sûr pour les performances). De plus, le mot atomique ne signifie pas * un * cycle d'un processeur. Cela signifie simplement que rien ne peut arriver à la variable entre les deux. FYI le modèle atomique peut être instancié avec des types aussi grands que vous voulez: "std :: atomic peut être instancié avec n'importe quel type T trivialCopyable". http://en.cppreference.com/w/cpp/atomic/atomic –

+0

Je comprends que (je suis à la fois développeur C et C++), mais pour expliquer simplement le sujet il m'a paru plus simple d'être plus proche du hardware , comme atomique doit être compris comme ses contreparties C (sig_atomic_t). c'était juste une simplification à des fins éducatives. – lemmel