Namespaces
Variants

Atomic types

From cppreference.net

Table des matières

Syntaxe

_Atomic ( type-name ) (1) (depuis C11)
_Atomic type-name (2) (depuis C11)
1) Utiliser comme spécificateur de type ; cela désigne un nouveau type atomique
2) Utiliser comme qualificateur de type ; cela désigne la version atomique de type-name . Dans ce rôle, il peut être combiné avec const , volatile , et restrict , bien que contrairement aux autres qualificateurs, la version atomique de type-name puisse avoir une taille, un alignement et une représentation d'objet différents.
type-name - tout type autre que tableau ou fonction. Pour (1) , type-name ne peut pas non plus être atomique ou qualifié cvr

L'en-tête <stdatomic.h> définit de nombreux alias de types pratiques , de atomic_bool à atomic_uintmax_t , qui simplifient l'utilisation de ce mot-clé avec les types intégrés et les types de bibliothèque.

_Atomic const int* p1;  // p est un pointeur vers un const int atomique
const atomic_int* p2;   // identique
const _Atomic(int)* p3; // identique

Si la macro constante __STDC_NO_ATOMICS__ est définie par le compilateur, le mot-clé _Atomic n'est pas fourni.

Explication

Les objets de types atomiques sont les seuls objets exempts de courses aux données ; c'est-à-dire qu'ils peuvent être modifiés par deux threads simultanément ou modifiés par un thread et lus par un autre.

Chaque objet atomique possède son propre ordre de modification associé, qui est un ordre total des modifications apportées à cet objet. Si, du point de vue d'un thread, la modification A d'un certain atomique M se produit-avant la modification B du même atomique M , alors dans l'ordre de modification de M , A se produit avant B .

Notez que bien que chaque objet atomique ait son propre ordre de modification, il n'existe pas d'ordre total unique ; différents threads peuvent observer les modifications d'objets atomiques différents dans des ordres différents.

Il existe quatre types de cohérence garantis pour toutes les opérations atomiques :

  1. Cohérence écriture-écriture : Si une opération A qui modifie un objet atomique M se produit avant une opération B qui modifie M , alors A apparaît avant B dans l'ordre de modification de M .
  2. Cohérence lecture-lecture : Si un calcul de valeur A d'un objet atomique M se produit avant un calcul de valeur B de M , et A prend sa valeur d'un effet secondaire X sur M , alors la valeur calculée par B est soit la valeur stockée par X , soit la valeur stockée par un effet secondaire Y sur M , où Y apparaît après X dans l'ordre de modification de M .
  3. Cohérence lecture-écriture : Si un calcul de valeur A d'un objet atomique M se produit avant une opération B sur M , alors A prend sa valeur d'un effet secondaire X sur M , où X apparaît avant B dans l'ordre de modification de M .
  4. Cohérence écriture-lecture : Si un effet secondaire X sur un objet atomique M se produit avant un calcul de valeur B de M , alors l'évaluation B prend sa valeur de X ou d'un effet secondaire Y qui apparaît après X dans l'ordre de modification de M .

Certaines opérations atomiques sont également des opérations de synchronisation ; elles peuvent avoir des sémantiques de libération supplémentaires, des sémantiques d'acquisition ou des sémantiques séquentiellement cohérentes. Voir memory_order .

Les opérateurs intégrés d'incrémentation et de décrémentation et d'affectation composée sont des opérations atomiques de lecture-modification-écriture avec un ordonnancement séquentiel cohérent total (comme s'ils utilisaient memory_order_seq_cst ). Si des sémantiques de synchronisation moins strictes sont souhaitées, les fonctions de la bibliothèque standard peuvent être utilisées à la place.

Les propriétés atomiques ne sont significatives que pour les expressions lvalue . La conversion lvalue-vers-rvalue (qui modélise une lecture de mémoire depuis un emplacement atomique vers un registre CPU) supprime l'atomicité ainsi que les autres qualificateurs.

Notes

Accéder à un membre d'une structure/union atomique est un comportement indéfini.

Le type de bibliothèque sig_atomic_t ne fournit pas de synchronisation inter-thread ni d'ordonnancement de la mémoire, seulement l'atomicité.

Les types volatile ne fournissent pas la synchronisation inter-threads, l'ordonnancement de la mémoire ou l'atomicité.

Il est recommandé que les implémentations garantissent que la représentation de _Atomic ( T ) en C soit identique à celle de std :: atomic < T > en C++ pour tout type possible T . Les mécanismes utilisés pour assurer l'atomicité et l'ordonnancement de la mémoire devraient être compatibles.

Mots-clés

_Atomic

Exemple

#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data)
{
    for (int n = 0; n < 1000; ++n)
    {
        ++cnt;
        ++acnt;
        // pour cet exemple, l'ordre de mémoire relâché est suffisant, par exemple
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}
int main(void)
{
    thrd_t thr[10];
    for (int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for (int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Sortie possible :

The atomic counter is 10000
The non-atomic counter is 8644

Références

  • Norme C23 (ISO/IEC 9899:2024):
  • 6.7.2.4 Spécificateurs de type atomique (p: TBD)
  • 7.17 Atomics <stdatomic.h> (p: TBD)
  • Norme C17 (ISO/CEI 9899:2018) :
  • 6.7.2.4 Spécificateurs de type atomique (p: 87)
  • 7.17 Atomics <stdatomic.h> (p: 200-209)
  • Norme C11 (ISO/CEI 9899:2011) :
  • 6.7.2.4 Spécificateurs de type atomique (p: 121)
  • 7.17 Atomics <stdatomic.h> (p: 273-286)

Voir aussi

Bibliothèque de support de la concurrence