Atomic types
Inhaltsverzeichnis |
Syntax
_Atomic
(
Typname
)
|
(1) | (seit C11) | |||||||
_Atomic
Typname
|
(2) | (seit C11) | |||||||
const
,
volatile
, und
restrict
kombiniert werden, obwohl im Gegensatz zu anderen Qualifizierern die atomare Version von
type-name
eine andere Größe, Ausrichtung und Objektdarstellung haben kann.
| type-name | - | jeder Typ außer Array oder Funktion. Für (1) darf type-name ebenfalls nicht atomic oder cvr-qualifiziert sein |
Der Header <stdatomic.h> definiert viele praktische Typaliase , von atomic_bool bis atomic_uintmax_t , die die Verwendung dieses Schlüsselworts mit eingebauten und Bibliothekstypen vereinfachen.
_Atomic const int* p1; // p ist ein Zeiger auf ein atomares const int const atomic_int* p2; // dasselbe const _Atomic(int)* p3; // dasselbe
Falls die Makrokonstante __STDC_NO_ATOMICS__ vom Compiler definiert wird, ist das Schlüsselwort _Atomic nicht verfügbar.
Erklärung
Objekte atomarer Typen sind die einzigen Objekte, die frei von Datenrennen sind; das heißt, sie können von zwei Threads gleichzeitig geändert oder von einem geändert und von einem anderen gelesen werden.
Jedes atomare Objekt hat seine eigene zugehörige
Modifikationsreihenfolge
, die eine totale Ordnung der an diesem Objekt vorgenommenen Modifikationen darstellt. Wenn aus der Sicht eines Threads die Modifikation
A
eines atomaren
M
happens-before
der Modifikation
B
desselben atomaren
M
, dann tritt in der Modifikationsreihenfolge von
M
,
A
vor
B
auf.
Beachten Sie, dass zwar jedes atomare Objekt seine eigene Modifikationsreihenfolge hat, es jedoch keine einzige Gesamtreihenfolge gibt; verschiedene Threads können Modifikationen an verschiedenen atomaren Objekten in unterschiedlicher Reihenfolge beobachten.
Es gibt vier Kohärenzarten, die für alle atomaren Operationen garantiert werden:
-
Write-Write-Kohärenz
: Wenn eine Operation
A, die ein atomares ObjektMmodifiziert, vor einer OperationBstattfindet, dieMmodifiziert, dann erscheintAvorBin der Modifikationsreihenfolge vonM. -
Read-Read-Kohärenz
: Wenn eine Werteberechnung
Aeines atomaren ObjektsMvor einer WerteberechnungBvonMstattfindet undAseinen Wert von einem NebeneffektXaufMbezieht, dann ist der vonBberechnete Wert entweder der vonXgespeicherte Wert oder der von einem NebeneffektYaufMgespeicherte Wert, wobeiYnachXin der Modifikationsreihenfolge vonMerscheint. -
Read-Write-Kohärenz
: Wenn eine Werteberechnung
Aeines atomaren ObjektsMvor einer OperationBaufMstattfindet, dann beziehtAseinen Wert von einem NebeneffektXaufM, wobeiXvorBin der Modifikationsreihenfolge vonMerscheint. -
Write-Read-Kohärenz
: Wenn ein Nebeneffekt
Xauf ein atomares ObjektMvor einer WerteberechnungBvonMstattfindet, dann bezieht die AuswertungBihren Wert vonXoder von einem NebeneffektY, der nachXin der Modifikationsreihenfolge vonMerscheint.
Einige atomare Operationen sind auch Synchronisationsoperationen; sie können zusätzliche Release-Semantik, Acquire-Semantik oder sequentiell-konsistente Semantik haben. Siehe memory_order .
Integrierte Inkrement- und Dekrementoperatoren und zusammengesetzte Zuweisungen sind atomare Lese-Modifizieren-Schreibe-Operationen mit vollständig sequentiell konsistenter Ordnung (als ob memory_order_seq_cst verwendet würde). Falls weniger strikte Synchronisationssemantik gewünscht ist, können stattdessen die Standardbibliotheksfunktionen verwendet werden.
Atomare Eigenschaften sind nur für Lvalue-Ausdrücke von Bedeutung. Die Lvalue-zu-Rvalue-Konvertierung (die einen Speicherlesevorgang von einem atomaren Ort in eine CPU-Register modelliert) entfernt die Atomarität zusammen mit anderen Qualifizierern.
|
Dieser Abschnitt ist unvollständig
Grund: mehr, Überprüfung der Interaktion mit memory_order und atomic library pages |
Hinweise
Der Zugriff auf ein Mitglied einer atomaren Struktur/Union ist undefiniertes Verhalten.
Der Bibliothekstyp sig_atomic_t bietet keine Thread-Synchronisation oder Speicherreihenfolge, lediglich Atomarität.
Die
volatile
-Typen bieten keine Thread-Synchronisation, Speicherreihenfolge oder Atomarität.
Es wird empfohlen, dass Implementierungen sicherstellen, dass die Darstellung von
_Atomic
(
T
)
in C identisch ist mit der von
std
::
atomic
<
T
>
in C++ für jeden möglichen Typ
T
. Die verwendeten Mechanismen zur Sicherstellung von Atomarität und Speicherreihenfolge sollten kompatibel sein.
Schlüsselwörter
Beispiel
#include <stdatomic.h> #include <stdio.h> #include <threads.h> atomic_int acnt; int cnt; int f(void* thr_data) { for (int n = 0; n < 1000; ++n) { ++cnt; ++acnt; // for this example, relaxed memory order is sufficient, e.g. // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); } 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 8644
Referenzen
- C23 Standard (ISO/IEC 9899:2024):
-
- 6.7.2.4 Atomic type specifiers (S.: TBD)
-
- 7.17 Atomics <stdatomic.h> (S.: TBD)
- C17-Standard (ISO/IEC 9899:2018):
-
- 6.7.2.4 Atomare Typbezeichner (S: 87)
-
- 7.17 Atomics <stdatomic.h> (S: 200-209)
- C11-Standard (ISO/IEC 9899:2011):
-
- 6.7.2.4 Atomic type specifiers (S. 121)
-
- 7.17 Atomics <stdatomic.h> (S. 273-286)
Siehe auch
| Concurrency Support Library | |
|
C++ documentation
für
atomic
|