N'est-ce pas ? atomic<bool>
redondant car bool
est atomique par nature ? Je ne pense pas qu'il soit possible d'avoir une valeur bool partiellement modifiée. Quand ai-je vraiment besoin d'utiliser atomic<bool>
au lieu de bool
?
Réponses
Trop de publicités?Non En C++, un type est "atomique par nature", sauf s'il s'agit d'un std::atomic*
- quelque chose. C'est parce que la norme le dit.
Dans la pratique, les instructions matérielles réelles qui sont émises pour manipuler une std::atomic<bool>
peuvent (ou non) être les mêmes que celles d'une entreprise ordinaire. bool
Mais être atomique est un concept plus large avec des ramifications plus importantes (par exemple, des restrictions sur le réordonnancement du compilateur). En outre, certaines opérations (comme la négation) sont surchargées sur l'opération atomique pour créer une instruction distincte sur le matériel par rapport à la séquence native, non atomique, de lecture-modification-écriture d'une variable non atomique.
Rappelez-vous barrières de mémoire . Bien qu'il soit impossible de changer bool
En partie, il est possible que le système multiprocesseur ait cette variable en plusieurs copies et qu'un thread puisse voir l'ancienne valeur même après qu'un autre thread l'ait changée en nouvelle. Atomic introduit une barrière de mémoire, donc cela devient impossible.
Les types atomiques du C++ traitent trois les problèmes potentiels. Premièrement, une lecture ou une écriture peut être déchirée par un changement de tâche si l'opération nécessite plus d'une opération de bus (et que peut à un bool
selon la manière dont elle est mise en œuvre). Deuxièmement, une lecture ou une écriture peut n'affecter que le cache associé au processeur qui effectue l'opération, et les autres processeurs peuvent avoir une valeur différente dans leur cache. Troisièmement, le compilateur peut réorganiser l'ordre des opérations si elles n'affectent pas le résultat (les contraintes sont un peu plus compliquées, mais c'est suffisant pour le moment).
Vous pouvez résoudre chacun de ces trois problèmes par vous-même en faisant des hypothèses sur la façon dont les types que vous utilisez sont implémentés, en vidant explicitement les caches, et en utilisant des options spécifiques au compilateur pour empêcher le réordonnancement (et, non, volatile
ne le fait pas, à moins que la documentation de votre compilateur ne l'indique).
Mais pourquoi passer par tout ça ? atomic
s'en occupe pour vous, et fait probablement un meilleur travail que ce que vous pouvez faire par vous-même.
Considérons une opération de comparaison et d'échange :
bool a = ...;
bool b = ...;
if (a)
swap(a,b);
Après avoir lu a, nous obtenons true, un autre thread pourrait arriver et mettre a false, nous échangeons alors (a,b), donc après la sortie b est false, même si l'échange a été fait.
Utilisation de std::atomic::compare_exchange
on peut faire toute la logique if/swap atomiquement de telle sorte que l'autre thread ne puisse pas mettre a à false entre le if et le swap (sans verrouillage). Dans une telle circonstance, si l'échange a été effectué, alors b doit être faux à la sortie.
Ce n'est qu'un exemple d'opération atomique qui s'applique à un type à deux valeurs tel que bool.
Les opérations atomiques ne se limitent pas aux valeurs déchirées, donc, bien que je sois d'accord avec vous et d'autres posteurs sur le fait que je ne connais pas d'environnement où les valeurs déchirées ne sont pas prises en compte. bool
est une possibilité, il y a plus en jeu.
Herb Sutter a donné une excellente conférence à ce sujet, que vous pouvez consulter en ligne. Attention, il s'agit d'un exposé long et complexe. Herb Sutter, Armes atomiques . Le problème se résume à éviter les courses de données car cela permet d'avoir l'illusion de la cohérence séquentielle.
- Réponses précédentes
- Plus de réponses