Namespaces
Variants

atomic_fetch_add, atomic_fetch_add_explicit

From cppreference.net
Definiert im Header <stdatomic.h>
C atomic_fetch_add ( volatile A * obj, M arg ) ;
(1) (seit C11)
C atomic_fetch_add_explicit ( volatile A * obj, M arg, memory_order order ) ;
(2) (seit C11)

Ersetzt atomar den Wert, auf den obj zeigt, durch das Ergebnis der Addition von arg zum alten Wert von obj , und gibt den zuvor in obj gespeicherten Wert zurück. Der Vorgang ist ein Lese-Modifizieren-Schreiben-Vorgang. Die erste Version ordnet Speicherzugriffe gemäß memory_order_seq_cst , die zweite Version ordnet Speicherzugriffe gemäß order .

Dies ist eine generische Funktion , die für alle atomaren Objekttypen A definiert ist. Das Argument ist ein Zeiger auf einen flüchtigen atomaren Typ, um Adressen sowohl von nicht-flüchtigen als auch flüchtigen (z.B. speichergemappten E/A) atomaren Objekten zu akzeptieren, und die flüchtige Semantik wird beibehalten, wenn diese Operation auf flüchtige atomare Objekte angewendet wird. M ist entweder der nicht-atomare Typ, der A entspricht, wenn A ein atomarer Ganzzahltyp ist, oder ptrdiff_t , wenn A ein atomarer Zeigertyp ist.

Es ist nicht spezifiziert, ob der Name einer generischen Funktion ein Makro oder ein mit externer Bindung deklarierter Bezeichner ist. Wenn eine Makrodefinition unterdrückt wird, um auf eine tatsächliche Funktion zuzugreifen (z. B. in Klammern gesetzt wie ( atomic_fetch_add ) ( ... ) ), oder ein Programm einen externen Bezeichner mit dem Namen einer generischen Funktion definiert, ist das Verhalten undefiniert.

Für vorzeichenbehaftete Ganzzahltypen ist die Arithmetik als Zweierkomplement-Darstellung definiert. Es gibt keine undefinierten Ergebnisse. Für Zeigertypen kann das Ergebnis eine undefinierte Adresse sein, aber die Operationen haben ansonsten kein undefiniertes Verhalten.

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 Speichersynchronisationsreihenfolge für diesen Vorgang: alle Werte sind erlaubt

Rückgabewert

Der zuvor vom atomaren Objekt, auf das obj zeigt, gehaltene Wert.

Beispiel

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>
atomic_int acnt;
int cnt;
int f(void* thr_data)
{
    for(int n = 0; n < 1000; ++n) {
        atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); // atomar
        ++cnt; // undefiniertes Verhalten, in der Praxis gehen einige Aktualisierungen verloren
    }
    return 0;
}
int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Mögliche Ausgabe:

The atomic counter is 10000
The non-atomic counter is 9511

Referenzen

  • C17-Standard (ISO/IEC 9899:2018):
  • 7.17.7.5 Die atomaren Abruf- und Modifizierungs-Generic-Funktionen (S: 208)
  • C11-Standard (ISO/IEC 9899:2011):
  • 7.17.7.5 Die atomic_fetch- und modify-Generic-Funktionen (S: 284-285)

Siehe auch

Atomare Subtraktion
(Funktion)
C++-Dokumentation für atomic_fetch_add , atomic_fetch_add_explicit