En C est “i + = 1;” atomique?

En C, i+=1; atomique?

    La norme C ne définit pas si elle est atomique ou non.

    En pratique, vous n’écrivez jamais de code qui échoue si une opération donnée est atomique, mais vous pouvez aussi écrire du code qui échoue si ce n’est pas le cas . Alors supposons que ce ne soit pas.

    Non.

    La seule opération garantie par le standard de langage C comme étant atomique consiste à atsortingbuer ou à récupérer une valeur dans / à partir d’une variable de type sig_atomic_t , définie dans .

    (C99, chapitre 7.14 Traitement du signal.)

    Défini en C, non. En pratique, peut-être. Ecris-le en assemblée.

    La norme ne donne aucune garantie.

    Par conséquent, un programme portable ne ferait pas l’hypothèse. Ce n’est pas clair si vous voulez dire “requirejs pour être atomique” ou “se trouve être atomique dans mon code C”, et la réponse à cette deuxième question est que cela dépend de beaucoup de choses:

    • Toutes les machines ne disposent même pas d’une mémoire incrémentée. Certains ont besoin de charger et de stocker la valeur pour pouvoir l’exploiter. La réponse est “jamais”.

    • Sur les ordinateurs dotés d’une mémoire incrémentée, rien ne garantit que le compilateur ne produira de toute façon pas de séquence de chargement, d’incrémentation ou de stockage, ni aucune autre instruction non atomique.

    • Sur les machines qui ont une opération d’augmentation de la mémoire, celle-ci peut être atomique ou non par rapport aux autres unités centrales.

    • Sur les machines disposant d’une mémoire d’augmentation atomique, il se peut que cette propriété ne soit pas spécifiée dans l’architecture, mais simplement comme une propriété d’une édition particulière de la puce du processeur, voire de certaines logiques de base ou conceptions de cartes mères.

    En ce qui concerne “comment procéder de manière atomique”, il existe généralement un moyen de procéder rapidement plutôt que de recourir à une exclusion mutuelle négociée (plus coûteuse). Parfois, cela implique des séquences de code répétables spéciales de détection de collision. Il est préférable de les implémenter dans un module de langage d’assemblage, car il s’agit de toute façon d’une cible spécifique, de sorte que le HLL ne présente aucun avantage en termes de portabilité.

    Enfin, comme les opérations atomiques ne nécessitant pas d’exclusion mutuelle négociée (coûteuse) sont rapides et donc utiles, et dans tous les cas nécessaires au code portable, les systèmes disposent généralement d’une bibliothèque, généralement écrite en assembleur, qui implémente déjà des fonctions similaires.

    Que l’expression soit atomique ou non dépend uniquement du code machine généré par le compilateur et de l’architecture de la CPU sur laquelle il sera exécuté. À moins que l’ajout ne puisse être réalisé dans une instruction machine, il est peu probable qu’il soit atomique.

    Si vous utilisez Windows, vous pouvez utiliser la fonction API InterlockedIncrement () pour effectuer un incrément atomique garanti. Il existe des fonctions similaires pour décrémenter, etc.

    Cela dépend vraiment de votre cible et du code mnémonique de votre processeur / uC. Si i est une variable détenue dans un registre, il est possible de l’avoir atomique.

    Bien que je ne sois pas nécessairement atomique pour le langage C, il convient de noter qu’il est atomique sur la plupart des plateformes. La documentation de la bibliothèque C GNU indique:

    En pratique, vous pouvez supposer que int et les autres types entiers ne dépassant pas int sont atomiques. Vous pouvez également supposer que les types de pointeurs sont atomiques; c’est très pratique. Ces deux hypothèses sont vraies sur toutes les machines sockets en charge par la bibliothèque GNU C et sur tous les systèmes POSIX connus.

    Non ce n’est pas. Si la valeur de i n’est pas déjà chargée dans l’un des registres, cela ne peut pas être fait dans une seule instruction d’assemblage.

    Le langage C / C ++ lui-même ne fait aucune déclaration d’atomicité. Vous devez vous appuyer sur des fonctions insortingnsèques ou des fonctions de bibliothèque pour assurer le comportement atomique.

    Il suffit de placer un mutex ou un sémaphore autour. Bien sûr, il n’est pas atomique et vous pouvez créer un programme de test avec environ 50 threads accédant à la même variable et l’incrémentant, pour le vérifier par vous-même.

    Pas habituellement.

    Si i est volatile , cela dépend de l’architecture et du compilateur de votre CPU. Si l’ajout de deux entiers dans la mémoire principale est atomique sur votre CPU, alors cette instruction C peut être atomique avec un volatile int i .

    Non, la norme C ne garantit pas l’atomicité et, en pratique, l’opération ne sera pas atomique. Vous devez utiliser une bibliothèque (par exemple, l’ API Windows ) ou des fonctions intégrées du compilateur ( GCC , MSVC ).

    La réponse à votre question dépend de savoir si i est une variable locale, static ou globale. Si i est une variable static ou globale, alors non, l’instruction i += 1 n’est pas atomique. Si, toutefois, i est une variable locale, l’instruction est atomique pour les systèmes d’exploitation modernes fonctionnant sous l’architecture x86 et probablement également avec d’autres architectures. @Dan Cristoloveanu était sur la bonne voie pour le cas de variable locale, mais il y a aussi plus à dire.

    (Dans ce qui suit, je suppose un système d’exploitation moderne avec une protection sur une architecture x86 avec un thread entièrement implémenté avec une commutation de tâches .)

    Étant donné qu’il s’agit d’un code C, la syntaxe i += 1 implique qu’il s’agisse d’une sorte de variable entière dont la valeur, s’il s’agit d’une variable locale, est stockée dans un registre tel que %eax ou dans la stack. Traitant le cas facile en premier, si la valeur de i est stockée dans un registre, disons %eax , le compilateur C traduira très probablement l’instruction en quelque chose comme:

     addl $1, %eax 

    ce qui est bien sûr atomique car aucun autre processus / thread ne devrait être capable de modifier le registre %eax du thread en cours d’exécution, et le thread lui-même ne peut plus modifier %eax tant que cette instruction n’est pas terminée.

    Si la valeur de i est stockée dans la stack, cela signifie qu’il y a une extraction en mémoire, une incrémentation et une validation. Quelque chose comme:

     movl -16(%esp), %eax addl $1, %eax movl %eax, -16(%esp) # this is the commit. It may actually come later if `i += 1` is part of a series of calculations involving `i`. 

    Normalement, cette série d’opérations n’est pas atomique. Cependant, sur un système d’exploitation moderne, les processus / threads ne doivent pas pouvoir modifier la stack d’un autre thread. Par conséquent, ces opérations sont terminées sans que d’autres processus puissent interférer. Ainsi, la déclaration i += 1 est également atomique.