Bibliothèque standard C++<atomic>

Dans la programmation multithread, la synchronisation des données et la sécurité des threads sont des questions importantes.

La norme C++11 a introduit<atomic>La bibliothèque fournit un ensemble d'opérations atomiques pour garantir que l'accès à un seul élément de données est atomique, c'est-à-dire indivisible, dans un environnement multithread. Cela permet d'éviter les courses de données et de garantir la sécurité des threads.

Les opérations atomiques sont des opérations qui ne peuvent pas être interrompues par d'autres threads pendant leur exécution.

<atomic>Les types atomiques de la bibliothèque fournissent de telles opérations, ce qui permet de garantir un accès sûr aux données partagées dans un environnement multithread.

Syntaxe

<atomic>La bibliothèque fournit divers types atomiques, notammentatomic<bool>, atomic<char>, atomic<short>, atomic<int>, atomic<long>, atomic<long long>, atomic<wchar_t>, atomic<char16_t>, atomic<char32_t>, atomic<unsigned char>, atomic<unsigned short>, atomic<unsigned>, atomic<unsigned long>, atomic<unsigned long long>, atomic<float>, atomic<double>, atomic<long double>etc.

Opérations de base

  • load(): lire en toute sécurité la valeur d'une variable atomique.
  • store(value): écrire en toute sécurité une valeur dans une variable atomique.
  • exchange(value): remplacer la valeur d'une variable atomique parvalue, et renvoyer l'ancienne valeur de la variable atomique.
  • compare_exchange_weak(expected, desired): si la valeur actuelle de la variable atomique est égale àexpected, puis la définir àdesired, et renvoietrue. Sinon, il vaexpectedDéfinir sur la valeur actuelle de la variable atomique, et renvoyer.false。
  • compare_exchange_strong(expected, desired): etcompare_exchange_weaksimilaire, mais boucle jusqu'à ce que cela réussisse.

Exemple

Ce qui suit est un exemple utilisant<atomic>Un exemple simple de la bibliothèque, montrant comment mettre à jour en toute sécurité un compteur partagé dans un environnement multi-thread.

Exemple

#include <iostream>
#include <atomic>
#include <thread>

std::atomic<int> counter(0); // Initialiser le compteur atomique

void increment() {
    for (int i = 0; i < 10000; ++i) {
        counter.fetch_add(1, std::memory_order_relaxed); // Incrémentation atomique
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Valeur finale du compteur : " << counter << std::endl; // Afficher la valeur finale du compteur

    return 0;
}

Exécutez le programme ci-dessus, vous verrez une sortie similaire à :

Final counter value: 20000

Cette sortie montre que les deux threads ont incrémenté avec succès la valeur du compteur 10000 fois chacun sans courses de données.

Notes

  • Utilisation<atomic>Lors de l'utilisation de la bibliothèque, il est nécessaire de garantir que tous les accès aux données partagées se font via des opérations atomiques afin d'éviter les courses de données.
  • Différentes opérations atomiques ont des exigences d'ordre mémoire différentes.std::memory_order_relaxedIl s'agit de l'exigence d'ordre mémoire la plus faible, mais elle peut ne pas garantir la visibilité des opérations. Choisissez un ordre mémoire approprié selon les besoins.
  • Le surcoût de performance des opérations atomiques est généralement plus élevé que celui des opérations non atomiques, donc dans un environnement monothread, l'utilisation de variables ordinaires peut être plus efficace.

en utilisant<atomic>Avec la bibliothèque, les programmeurs C++ peuvent plus facilement écrire du code thread-safe tout en maintenant des performances élevées.

autres extensions