162 votes

Est-ce que num++ peut être atomique pour 'int num' ?

En général, pour int num , num++ (o ++num ), comme une opération de lecture-modification-écriture, est non atomique . Mais je vois souvent des compilateurs, par exemple CCG et génère le code suivant ( essayez ici ):

void f()
{

  int num = 0;
  num++;
}

f():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        add     DWORD PTR [rbp-4], 1
        nop
        pop     rbp
        ret

Depuis la ligne 5, qui correspond à num++ est une instruction, peut-on conclure que num++ est atomique dans cette affaire ?

Et si oui, cela veut-il dire que les produits ainsi générés num++ peut être utilisé dans des scénarios concurrents (multithreads) sans risque de course aux données (c'est-à-dire que nous n'avons pas besoin de le fabriquer, par exemple, std::atomic<int> et imposer les coûts associés, puisque c'est de toute façon atomique) ?

UPDATE

Remarquez que cette question est pas si l'incrémentation es atomique (ce n'est pas le cas et c'était et c'est toujours la première ligne de la question). Il s'agit de savoir si elle puede dans des scénarios particuliers, c'est-à-dire si la nature d'une seule instruction peut, dans certains cas, être exploitée pour éviter l'overhead de l'algorithme d'analyse de l'information. lock préfixe. Et, comme le mentionne la réponse acceptée dans la section sur les machines uniprocesseur, ainsi que cette réponse , la conversation dans ses commentaires et d'autres expliquent, il peut (mais pas avec C ou C++).

68 votes

Qui vous a dit que add est atomique ?

6 votes

Étant donné que l'une des caractéristiques de l'atomique est la prévention de types spécifiques de réordonnancement pendant l'optimisation, non, indépendamment de l'atomicité de l'opération réelle

1 votes

Il se peut que votre compilateur voit que num++ peut être optimisé à cela parce que vous n'utilisez pas la valeur de retour de num++.

2voto

Asu Points 1422

Que la sortie d'un seul compilateur, sur une architecture CPU spécifique, avec des optimisations désactivées (puisque gcc ne compile même pas ++ a add lors de l'optimisation dans un exemple rapide et concret ), semble impliquer que l'incrémentation de cette manière est atomique, ce qui ne signifie pas qu'elle est conforme à la norme (vous provoquerez un comportement non défini en essayant d'accéder à la fonction num dans un fil de discussion), et est de toute façon erronée, parce que add es pas atomique en x86.

Notez que les atomiques (qui utilisent le lock préfixe d'instruction) sont relativement lourdes sur x86 ( voir cette réponse pertinente ), mais toujours remarquablement moins qu'un mutex, qui n'est pas très approprié dans ce cas d'utilisation.

Les résultats suivants sont tirés de clang++ 3.8 lors de la compilation avec -Os .

Incrémenter un int par référence, la manière "normale" :

void inc(int& x)
{
    ++x;
}

Cela se compile en :

inc(int&):
    incl    (%rdi)
    retq

Incrémenter un int passé par référence, de manière atomique :

#include <atomic>

void inc(std::atomic<int>& x)
{
    ++x;
}

Cet exemple, qui n'est pas beaucoup plus complexe que la méthode habituelle, permet simplement d'obtenir l'adresse de l'utilisateur. lock ajouté au préfixe incl mais attention, comme il a été dit précédemment, il s'agit de pas bon marché. Ce n'est pas parce qu'un assemblage semble court qu'il est rapide.

inc(std::atomic<int>&):
    lock            incl    (%rdi)
    retq

-2voto

Bonita Montero Points 172

Lorsque votre compilateur n'utilise qu'une seule instruction pour l'incrément et que votre machine est monofilaire, votre code est sûr. ^^

-3voto

Xirema Points 677

Essayez de compiler le même code sur une machine non-x86, et vous verrez rapidement des résultats d'assemblage très différents.

La raison num++ apparaît pour être atomique est parce que sur les machines x86, l'incrémentation d'un entier de 32 bits est, en fait, atomique (en supposant qu'aucune récupération de mémoire n'a lieu). Mais ceci n'est pas garanti par la norme c++, et il est peu probable que ce soit le cas sur une machine qui n'utilise pas le jeu d'instructions x86. Ainsi, ce code n'est pas à l'abri des conditions de course sur toutes les plates-formes.

Vous n'avez pas non plus la garantie que ce code est à l'abri des Race Conditions, même sur une architecture x86, car x86 n'effectue pas de chargements et de stockages en mémoire à moins d'y être spécifiquement invité. Ainsi, si plusieurs threads essayaient de mettre à jour cette variable simultanément, ils pourraient finir par incrémenter des valeurs en cache (périmées).

La raison, alors, que nous avons std::atomic<int> et ainsi de suite, de sorte que lorsque vous travaillez avec une architecture où l'atomicité des calculs de base n'est pas garantie, vous disposez d'un mécanisme qui forcera le compilateur à générer du code atomique.

0 votes

"La raison en est que sur les machines x86, l'incrémentation d'un entier de 32 bits est, en fait, atomique" pouvez-vous fournir un lien vers une documentation qui le prouve ?

8 votes

Il n'est pas non plus atomique sur x86. Il est sûr pour un seul cœur, mais s'il y a plusieurs cœurs (et c'est le cas), il n'est pas du tout atomique.

0 votes

Est-ce que x86 add réellement garanti atomique ? Je ne serais pas surpris si les incréments de registre étaient atomiques, mais cela n'est guère utile ; pour que l'incrément de registre soit visible par un autre thread, il doit être en mémoire, ce qui nécessiterait des instructions supplémentaires pour le charger et le stocker, supprimant ainsi l'atomicité. Je crois comprendre que c'est la raison pour laquelle la fonction lock existe pour les instructions ; le seul atome utile add s'applique à la mémoire déréférencée et utilise la méthode lock préfixe permettant de s'assurer que la ligne de cache est verrouillée pendant la durée de l'opération .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X