std:: atomic_compare_exchange_weak, std:: atomic_compare_exchange_strong, std:: atomic_compare_exchange_weak_explicit, std:: atomic_compare_exchange_strong_explicit
|
Défini dans l'en-tête
<atomic>
|
||
|
template
<
class
T
>
bool
atomic_compare_exchange_weak
|
(1) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_weak
|
(2) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_strong
|
(3) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_strong
|
(4) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_weak_explicit
|
(5) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_weak_explicit
|
(6) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_strong_explicit
|
(7) | (depuis C++11) |
|
template
<
class
T
>
bool
atomic_compare_exchange_strong_explicit
|
(8) | (depuis C++11) |
Compare atomiquement la représentation d'objet (jusqu'à C++20) représentation de valeur (depuis C++20) de l'objet pointé par obj avec celle de l'objet pointé par expected , et si elles sont égales bit à bit, remplace la première par desired (effectue une opération de lecture-modification-écriture). Sinon, charge la valeur actuelle pointée par obj dans * expected (effectue une opération de chargement).
| Surcharges | Modèle de mémoire pour | |
|---|---|---|
| opération de lecture‑modification‑écriture | opération de chargement | |
| (1-4) | std:: memory_order_seq_cst | std:: memory_order_seq_cst |
| (5-8) | success | failure |
Ces fonctions sont définies en termes de fonctions membres de std::atomic :
Si failure est plus fort que success ou (jusqu'à C++17) est l'un de std:: memory_order_release et std:: memory_order_acq_rel , le comportement est indéfini.
Table des matières |
Paramètres
| obj | - | pointeur vers l'objet atomique à tester et modifier |
| expected | - | pointeur vers la valeur attendue dans l'objet atomique |
| desired | - | valeur à stocker dans l'objet atomique si elle correspond à celle attendue |
| success | - | ordonnancement de synchronisation mémoire pour l'opération de lecture-modification-écriture si la comparaison réussit |
| failure | - | ordonnancement de synchronisation mémoire pour l'opération de chargement si la comparaison échoue |
Valeur de retour
Le résultat de la comparaison : true si * obj était égal à * expected , false sinon.
Notes
std::atomic_compare_exchange_weak
et
std::atomic_compare_exchange_weak_explicit
(les versions faibles) peuvent échouer de manière sporadique, c'est-à-dire agir comme si
*
obj
!
=
*
expected
même s'ils sont égaux. Lorsqu'une opération compare-and-exchange est dans une boucle, elles offrent de meilleures performances sur certaines plateformes.
Lorsqu'un échange-comparaison faible nécessiterait une boucle et qu'un échange-comparaison fort ne le nécessiterait pas, ce dernier est préférable, sauf si la représentation objet de
T
peut inclure
des bits de remplissage,
(jusqu'au C++20)
des bits de piège, ou offre plusieurs représentations objet pour la même valeur (par exemple, NaN en virgule flottante). Dans ces cas, l'échange-comparaison faible fonctionne généralement car il converge rapidement vers une représentation objet stable.
Pour une union dont certains bits participent aux représentations de valeur de certains membres mais pas d'autres, la comparaison-et-échange peut toujours échouer car ces bits de remplissage ont des valeurs indéterminées lorsqu'ils ne participent pas à la représentation de valeur du membre actif.
|
Les bits de remplissage qui ne participent jamais à la représentation de la valeur d'un objet sont ignorés. |
(since C++20) |
Exemple
Les opérations de comparaison et d'échange sont souvent utilisées comme blocs de construction fondamentaux des structures de données sans verrou.
#include <atomic> template<class T> struct node { T data; node* next; node(const T& data) : data(data), next(nullptr) {} }; template<class T> class stack { std::atomic<node<T>*> head; public: void push(const T& data) { node<T>* new_node = new node<T>(data); // put the current value of head into new_node->next new_node->next = head.load(std::memory_order_relaxed); // now make new_node the new head, but if the head // is no longer what's stored in new_node->next // (some other thread must have inserted a node just now) // then put that new head into new_node->next and try again while (!std::atomic_compare_exchange_weak_explicit( &head, &new_node->next, new_node, std::memory_order_release, std::memory_order_relaxed)) ; // the body of the loop is empty // note: the above loop is not thread-safe in at least // GCC prior to 4.8.3 (bug 60272), clang prior to 2014-05-05 (bug 18899) // MSVC prior to 2014-03-17 (bug 819819). See member function version for workaround } }; int main() { stack<int> s; s.push(1); s.push(2); s.push(3); }
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement correct |
|---|---|---|---|
| P0558R1 | C++11 |
une correspondance exacte de type était requise car
T
était déduit de multiples arguments
|
T
est uniquement déduit
de obj |
Voir aussi
|
compare atomiquement la valeur de l'objet atomique avec l'argument non atomique et effectue un échange atomique si égal ou un chargement atomique sinon
(fonction membre publique de
std::atomic<T>
)
|
|
|
(C++11)
(C++11)
|
remplace atomiquement la valeur de l'objet atomique par l'argument non atomique et retourne l'ancienne valeur de l'atome
(modèle de fonction) |
|
(obsolète en C++20)
(supprimé en C++26)
|
spécialise les opérations atomiques pour std::shared_ptr
(modèle de fonction) |
|
Documentation C
pour
atomic_compare_exchange
,
atomic_compare_exchange_explicit
|
|