Quand ai-je vraiment besoin d’utiliser au lieu de bool?

Est-ce que l’ atomic n’est pas redondant parce que bool est atomique par nature? Je ne pense pas qu’il soit possible d’avoir une valeur de bool partiellement modifiée. Quand ai-je vraiment besoin d’utiliser atomic au lieu de bool ?

Aucun type en C ++ n’est “atomique par nature” à moins qu’il ne s’agisse d’un std::atomic* -something. C’est parce que la norme le dit.

En pratique, les instructions matérielles émises pour manipuler un std::atomic peuvent être (ou non) identiques à celles d’un bool ordinaire, mais être atomique est un concept plus large avec des ramifications plus larges (par exemple, des ressortingctions sur recomposition du compilateur). De plus, certaines opérations (comme la négation) sont surchargées lors de l’opération atomique pour créer une instruction distinctement différente sur le matériel que la séquence native non-atomique de lecture-modification-écriture d’une variable non atomique.

Rappelez-vous des obstacles de mémoire . Bien qu’il soit impossible de changer partiellement de bool , 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é en nouveau. Atomic introduit une barrière de mémoire, donc cela devient impossible.

Les types atomiques de C ++ traitent trois problèmes potentiels. Tout d’abord, une lecture ou une écriture peut être déchirée par un changement de tâche si l’opération nécessite plusieurs opérations de bus (et cela peut arriver à un bool , selon la manière dont elle est implémentée). Deuxièmement, une lecture ou une écriture peut affecter uniquement le cache associé au processeur qui effectue l’opération, et d’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 l’instant).

Vous pouvez gérer chacun de ces trois problèmes en posant des hypothèses sur la manière 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, pas du tout). ceci à moins que votre documentation de compilateur ne le dise).

Mais pourquoi passer par tout ça? atomic occupe pour vous et fait probablement un meilleur travail que vous ne pouvez le faire vous-même.

Les opérations atomiques ne se limitent pas à des valeurs déchirées, alors même si je suis d’accord avec vous et avec d’autres affiches, je ne suis pas au courant d’un environnement où le bool déchiré est une possibilité.

Herb Sutter a très bien parlé de cela, que vous pouvez consulter en ligne. Soyez averti, c’est une conversation longue et complexe. Herb Sutter, armes atomiques . La question se résume à éviter les courses de données car cela vous permet d’avoir l’illusion d’une cohérence séquentielle.

Considérons une opération de comparaison et d’échange:

 bool a = ...; bool b = ...; if (a) swap(a,b); 

Après avoir lu a, on devient vrai, un autre thread peut arriver et mettre un faux, on échange alors (a, b), donc après exit b est faux, même si le swap a été fait.

En utilisant std::atomic::compare_exchange nous pouvons faire la logique if / swap complète de manière à ce que l’autre thread ne puisse pas définir un à false entre le if et le swap (sans locking). Dans un tel cas, si le swap a été effectué, b doit être faux à la sortie.

Ceci est juste un exemple d’une opération atomique qui s’applique à un type à deux valeurs tel que bool.

L’atomicité de certains types dépend exclusivement du matériel sous-jacent. Chaque architecture de processeur a différentes garanties quant à l’atomicité de certaines opérations. Par exemple:

Le processeur Intel486 (et les nouveaux processeurs depuis) ​​garantit que les opérations de mémoire de base suivantes seront toujours effectuées de manière atomique:

  • Lire ou écrire un octet
  • Lire ou écrire un mot aligné sur une limite de 16 bits
  • Lecture ou écriture d’un mot double aligné sur une limite de 32 bits

D’autres architectures ont des spécifications différentes sur lesquelles les opérations sont atomiques.

C ++ est un langage de programmation de haut niveau qui s’efforce de vous extraire du matériel sous-jacent. Pour cette raison, la norme ne peut tout simplement pas permettre de s’appuyer sur de telles hypothèses de bas niveau, sinon votre application ne serait pas portable. En conséquence, tous les types primitifs de C ++ sont fournis avec atomic contreparties atomic conformes à la bibliothèque standard compatible C ++ 11.