web-dev-qa-db-fra.com

Comportement atomique des opérateurs d'incréments unaires

Quelque part, j'ai lu que les opérateurs unaires sont par nature atomiques et peuvent donc être utilisés tels quels dans un environnement multi-thread. Pour confirmer la même chose, j’ai écrit deux programmes distincts où 

  1. J'ai utilisé une variable x et incrémenté à l'aide d'un opérateur unaire ++ x
  2. J'ai utilisé une variable x et incrémenté en utilisant x = x + 1

J'ai comparé le désassemblage des deux programmes et n'ai trouvé aucune différence. S'il vous plaît fournir vos contributions à ce sujet.

8
user3505805

Quelque part, j'ai lu que les opérateurs unaires sont par nature atomiques et peuvent donc être utilisés tels quels dans un environnement multi-thread. 

Cette source est complètement fausse. Vous devez utiliser std::atomic (ou l'équivalent C) pour obtenir l'atomicité - les opérations unaires ne sont pas spéciales.


J'ai comparé le désassemblage des deux programmes et n'ai trouvé aucune différence

Cela ne signifie pas que les opérations générées sont atomiques. Il n'y a pas de différence, car tout compilateur décent optimisera x=x+1 et ++x dans le même assemblage (en supposant les types intégrés).

13
Vittorio Romeo

Lorsque vous écrivez en C++ multiplateforme, vous n’avez que le comportement atomique lorsque vous utilisez std::atomic<>

Il est vrai que sur certaines plates-formes, comme Intel 64 bits, le processeur garantit que inc est atomique. Cependant, veuillez ne pas écrire de code qui en dépend! En tant que futur débogueur, je voudrais savoir quelles données sont destinées à être partagées via des threads et lesquelles ne le sont pas. 

Utiliser std::atomic<int> pourrait être un peu plus de travail à écrire, cependant, cela garantit que tout se comporte de manière atomique (sur chaque plate-forme) en revenant aux exigences de la plate-forme ( std :: atomic :: is_lock_free ) ou explicitement mettre un verrou autour de l'accès. Il insère également des gardes afin de s’assurer que les caches des autres cœurs de processeur sont invalidés (si la plate-forme le requiert).

En pratique pour Intel 64 bits, cela devrait vous donner le même assemblage, sinon, notez un bogue sur votre compilateur.

En même temps, certaines opérations avec ints peuvent ne pas être atomiques (opérateur * =), std::atomic ne les tient tout simplement pas, vous obligeant à les utiliser correctement.

Remarque: ++x et x = x+1 sont des opérations différentes, elles peuvent être optimisées pour le même assemblage. Compte tenu des exigences de la plate-forme non atomique, le second problème est soudain un bogue qui prend des jours à résoudre.

5
JVApen

L'affirmation selon laquelle un opérateur unaire est nécessairement atomique est un mythe.

Par exemple, ++x requiert une lecture et une écriture dans x pour que le risque d’une course de données s’ouvre.

Le fait que ++x soit compilé dans le même code que x = x + 1 n'est pas pertinent.

Si vous souhaitez éviter les courses de données, utilisez des types atomiques ou des unités d'exclusion mutuelles si un type atomique approprié n'est pas disponible. Pour éviter tout doute, int n'est pas nécessairement un type atomique.

5
Bathsheba

Quelque part, j’ai lu que les opérateurs unaires sont de nature atomique, et donc ils peut être utilisé tel quel dans un environnement multi-threadé.

C'est faux. x++, par exemple, nécessite une charge de x, un add et un magasin de x. Ces instructions ne sont pas atomiques par nature.

4
Sombrero Chicken

Pas vrai. Même si c'était le cas, quelle raison https://en.cppreference.com/w/cpp/atomic/atomic#Type_aliases a alors? 

Je pense que ce qu’ils voulaient dire, c’est probablement qu’un calcul sur une telle opération est généralement très minutieux et qu’il est donc fort probable qu’il n’ya jamais de situation de concurrence critique, ce qui est généralement vrai dans le code live, dans lequel vous ne calculez pas simultanément x ++ sur 4 pour des boucles.

2
anon

Vous n'avez pas spécifié le type de x. 

  1. Si x est un entier de 32 bits lorsque la plate-forme est de 16 ou 8 bits, l'opération 'x ++' Effectuera définitivement plusieurs opérations.
  2. x pourrait même ne pas être un type de base, x pourrait être une instance de classe où opérateur ++ fait des choses beaucoup plus compliquées que d'incrémenter un entier
2
Vladimir A.

Le caractère atomique de l'opération dépend du système cible. Une opération unaire peut ne pas être atomique sur les systèmes RMW tels que les micro contrôleurs RISC.

Il n'y a pas de réponse générique unique à cette question.

1
P__J__

Vous faites une hypothèse sur le code généré, si une seule instruction est générée, oui, ce sera atomique, sinon non.

Dans votre cas, cela suppose que le processeur cible ait l'instruction inc <address> et que le compilateur la produise.

0
bruno

Comportement atomique des opérateurs unaires

En C, les __/__ correctifs ++ ne sont pas unary-operators tels que & * + - ~ !. mais fait partie d'une expression unaire . Donc, le titre de la question est incompatible avec le corps.

Même un opérateur unaire tel que + n'est pas atomique, car l'accès à l'objet (pensez long long) permet d'effectuer plusieurs lectures de code op.

0
chux