Namensräume
Varianten
Aktionen

std::atomic_fetch_add, std::atomic_fetch_add_explicit

Von cppreference.com
< cpp‎ | atomic
 
 
Bibliothek für nebenläufige Programmierung
Threads
(C++11)
(C++20)
this_thread Namespace
(C++11)
(C++11)
(C++11)
Kooperatives Beenden
Gegenseitiger Ausschluss
(C++11)
Allgemeines Sperrungsmanagement
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Bedingungsvariablen
(C++11)
Semaphoren
Latches und Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
(C++11)
Sichere Wiederherstellung
(C++26)
Hazard Pointer
Atomare Typen
(C++11)
(C++20)
Initialisierung von atomaren Typen
(C++11)(veraltet in C++20)
(C++11)(veraltet in C++20)
Speicherordnung
(C++11)(deprecated in C++26)
Freie Funktionen für atomare Operationen
atomic_fetch_addatomic_fetch_add_explicit
(C++11)(C++11)
Freie Funktionen für atomare Flags
 
Definiert in Header <atomic>
template< class T >

T atomic_fetch_add( std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
(1) (seit C++11)
template< class T >

T atomic_fetch_add( volatile std::atomic<T>* obj,

                    typename std::atomic<T>::difference_type arg ) noexcept;
(2) (seit C++11)
template< class T >

T atomic_fetch_add_explicit( std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;
(3) (seit C++11)
template< class T >

T atomic_fetch_add_explicit( volatile std::atomic<T>* obj,
                             typename std::atomic<T>::difference_type arg,

                             std::memory_order order ) noexcept;
(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:

1,2) obj->fetch_add(arg)
3,4) obj->fetch_add(arg, order)

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, weil
T aus mehreren Argumenten abgeleitet wurde
T wird nur abgeleitet
von 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>) [edit]
subtrahiert einen nicht-atomaren Wert von einem atomaren Objekt und gibt den vorherigen Wert des atomaren Objekts zurück
(Funktions-Template) [bearbeiten]
C-Dokumentation für atomic_fetch_add, atomic_fetch_add_explicit