std:: atomic_fetch_add, std:: atomic_fetch_add_explicit
|
Definiert im 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 Wert zurück, der zuvor in obj gespeichert war. Die Operation wird so ausgeführt, als ob Folgendes ausgeführt würde:
Wenn
std::atomic<T>
kein
fetch_add
Mitglied hat (dieses Mitglied wird nur für
integrale
,
Gleitkomma-
(seit C++20)
und
Zeiger
Typen außer
bool
bereitgestellt), ist das Programm fehlerhaft.
Inhaltsverzeichnis |
Parameter
| obj | - | Zeiger auf das atomare Objekt, das modifiziert werden soll |
| arg | - | der Wert, der zum im atomaren Objekt gespeicherten Wert addiert werden soll |
| order | - | die Speichersynchronisierungsreihenfolge |
Rückgabewert
Der Wert unmittelbar vor den Auswirkungen dieser Funktion in der modification order von * obj .
Beispiel
Ein Single-Writer/Multiple-Reader-Lock kann mit
std::atomic_fetch_add
implementiert werden. Beachten Sie, dass diese einfache Implementierung nicht sperrfrei ist.
#include <atomic> #include <chrono> #include <iostream> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; // Bedeutung von cnt: // 5: Leser und Writer im Wettlauf. Keine aktiven Leser oder Writer. // 4...0: Es gibt 1...5 aktive Leser. Der Writer ist blockiert. // -1: Writer hat den Wettlauf gewonnen und Leser sind blockiert. const int N = 5; // Vier parallele Leser sind erlaubt std::atomic<int> cnt(N); std::vector<int> data; void reader(int id) { for (;;) { // Sperren while (std::atomic_fetch_sub(&cnt, 1) <= 0) std::atomic_fetch_add(&cnt, 1); // Lesen if (!data.empty()) std::cout << ("reader " + std::to_string(id) + " sees " + std::to_string(*data.rbegin()) + '\n'); if (data.size() == 25) break; // Entsperren std::atomic_fetch_add(&cnt, 1); // Pause std::this_thread::sleep_for(1ms); } } void writer() { for (int n = 0; n < 25; ++n) { // Sperren while (std::atomic_fetch_sub(&cnt, N + 1) != N) std::atomic_fetch_add(&cnt, N + 1); // Schreiben data.push_back(n); std::cout << "writer pushed back " << n << '\n'; // Entsperren 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
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 |
exakte Typübereinstimmung war erforderlich, weil
T
von mehreren Argumenten abgeleitet wurde
|
T
wird nur
von obj abgeleitet |
Siehe auch
|
addiert atomar das Argument zum im atomaren Objekt gespeicherten Wert 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 erhält den vorherigen Wert des atomaren Objekts
(Funktions-Template) |
|
C-Dokumentation
für
atomic_fetch_add
,
atomic_fetch_add_explicit
|
|