std::atomic_fetch_add, std::atomic_fetch_add_explicit
| Definiert in Header <atomic> |
||
| template< class T > T atomic_fetch_add( std::atomic<T>* obj, |
(1) | (seit C++11) |
| template< class T > T atomic_fetch_add( volatile std::atomic<T>* obj, |
(2) | (seit C++11) |
| template< class T > T atomic_fetch_add_explicit( std::atomic<T>* obj, |
(3) | (seit C++11) |
| template< class T > T atomic_fetch_add_explicit( volatile std::atomic<T>* obj, |
(4) | (seit C++11) |
Führt eine atomare Addition durch. Addiert atomar arg zu dem Wert, auf den obj zeigt, und gibt den vorherigen Wert zurück, den obj enthielt. Die Operation wird so ausgeführt, als ob Folgendes ausgeführt worden wäre:
Wenn std::atomic<T> keine fetch_add-Mitgliedsfunktion hat (dieses Mitglied wird nur für ganzzahlige, Gleitkomma-(seit C++20) und Zeigertypen außer bool bereitgestellt), ist das Programm schlecht formuliert.
Inhalt |
[edit] Parameter
| obj | - | Zeiger auf das zu modifizierende atomare Objekt |
| arg | - | Der Wert, der zum Wert im atomaren Objekt addiert werden soll. |
| Reihenfolge | - | die Speicher-Synchronisationsreihenfolge |
[edit] Rückgabewert
Der Wert, der den Effekten dieser Funktion in der Modifikationsreihenfolge von *obj unmittelbar vorausging.
[edit] Beispiel
Ein Lock für einen einzelnen Schreiber/mehrere Leser kann mit std::atomic_fetch_add erstellt werden. Beachten Sie, dass diese simplistische Implementierung nicht "lockout-free" ist.
#include <atomic> #include <chrono> #include <iostream> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; // meaning of cnt: // 5: readers and writer are in race. There are no active readers or writers. // 4...0: there are 1...5 active readers, The writer is blocked. // -1: writer won the race and readers are blocked. const int N = 5; // four concurrent readers are allowed std::atomic<int> cnt(N); std::vector<int> data; void reader(int id) { for (;;) { // lock while (std::atomic_fetch_sub(&cnt, 1) <= 0) std::atomic_fetch_add(&cnt, 1); // read if (!data.empty()) std::cout << ("reader " + std::to_string(id) + " sees " + std::to_string(*data.rbegin()) + '\n'); if (data.size() == 25) break; // unlock std::atomic_fetch_add(&cnt, 1); // pause std::this_thread::sleep_for(1ms); } } void writer() { for (int n = 0; n < 25; ++n) { // lock while (std::atomic_fetch_sub(&cnt, N + 1) != N) std::atomic_fetch_add(&cnt, N + 1); // write data.push_back(n); std::cout << "writer pushed back " << n << '\n'; // unlock std::atomic_fetch_add(&cnt, N + 1); // pause std::this_thread::sleep_for(1ms); } } int main() { std::vector<std::thread> v; for (int n = 0; n < N; ++n) v.emplace_back(reader, n); v.emplace_back(writer); for (auto& t : v) t.join(); }
Ausgabe
writer pushed back 0 reader 2 sees 0 reader 3 sees 0 reader 1 sees 0 <...> reader 2 sees 24 reader 4 sees 24 reader 1 sees 24
[edit] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| P0558R1 | C++11 | exakter Typabgleich war erforderlich, weilT aus mehreren Argumenten abgeleitet wurde |
T wird nur abgeleitetvon obj |
[edit] Siehe auch
| addiert atomar das Argument zum Wert, der im atomaren Objekt gespeichert ist, und erhält den zuvor gehaltenen Wert (öffentliche Mitgliedsfunktion von std::atomic<T>) | |
| (C++11)(C++11) |
subtrahiert einen nicht-atomaren Wert von einem atomaren Objekt und gibt den vorherigen Wert des atomaren Objekts zurück (Funktions-Template) |