std:: atomic_thread_fence
|
Definiert in Header
<atomic>
|
||
|
extern
"C"
void
atomic_thread_fence
(
std::
memory_order
order
)
noexcept
;
|
(seit C++11) | |
Legt die Speichersynchronisationsreihenfolge von nicht-atomaren und entspannten atomaren Zugriffen fest, wie durch order angegeben, ohne eine zugehörige atomare Operation. Beachten Sie jedoch, dass mindestens eine atomare Operation erforderlich ist, um die Synchronisation einzurichten, wie unten beschrieben.
Inhaltsverzeichnis |
Fence-Atomare Synchronisierung
Ein Release-Fence
F
in Thread
A
synchronisiert mit atomarer
Acquire-Operation
Y
in Thread
B
, wenn
-
es existiert ein atomarer Store
X(mit beliebiger Speicherreihenfolge), -
Yliest den vonXgeschriebenen Wert (oder den Wert, der von einer Release-Sequenz mit StartpunktXgeschrieben würde, fallsXeine Release-Operation wäre), -
Fist vorXin ThreadAsequenziert.
In diesem Fall werden alle nicht-atomaren und entspannten atomaren Speichervorgänge, die
sequenced-before
F
in Thread
A
sind,
happen-before
allen nicht-atomaren und entspannten atomaren Ladevorgängen von denselben Speicherorten in Thread
B
nach
Y
.
Atomare-Fence-Synchronisation
Eine atomare
Release-Operation
X
in Thread
A
synchronisiert sich mit einem Acquire-Fence
F
in Thread
B
, wenn
-
es existiert ein atomarer Lesevorgang
Y(mit beliebiger Speicherreihenfolge), -
Yliest den vonXgeschriebenen Wert (oder von der von X angeführten Release-Sequenz ), -
Yist in ThreadBvorFsequenziert.
In diesem Fall werden alle nicht-atomaren und relaxed atomaren Speichervorgänge, die
sequenced-before
X
in Thread
A
sind,
happen-before
allen nicht-atomaren und relaxed atomaren Ladevorgängen von denselben Speicherstellen in Thread
B
nach
F
.
Fence-Fence-Synchronisation
Ein Release-Fence
FA
in Thread
A
synchronisiert mit einem Acquire-Fence
FB
in Thread
B
, wenn
-
es existiert ein atomares Objekt
M, -
es existiert ein atomarer Schreibzugriff
X(mit beliebiger Speicherreihenfolge), derMin ThreadAmodifiziert, -
FAist sequenced-beforeXin ThreadA, -
es existiert ein atomarer Lesezugriff
Y(mit beliebiger Speicherreihenfolge) in ThreadB, -
Yliest den vonXgeschriebenen Wert (oder den Wert, der durch die release sequence headed byXgeschrieben würde, fallsXeine release-Operation wäre), -
Yist sequenced-beforeFBin ThreadB.
In diesem Fall werden alle nicht-atomaren und entspannten atomaren Speichervorgänge, die
sequenced-before
FA
in Thread
A
sind,
happen-before
allen nicht-atomaren und entspannten atomaren Ladevorgängen von denselben Speicherstellen in Thread
B
nach
FB
.
Abhängig vom Wert des order Parameters sind die Auswirkungen dieses Aufrufs:
- Wenn order == std:: memory_order_relaxed , gibt es keine Auswirkungen.
- Wenn order == std:: memory_order_acquire oder order == std:: memory_order_consume , handelt es sich um einen Acquire-Fence.
- Wenn order == std:: memory_order_release , handelt es sich um einen Release-Fence.
- Wenn order == std:: memory_order_acq_rel , handelt es sich sowohl um einen Release-Fence als auch um einen Acquire-Fence.
- Wenn order == std:: memory_order_seq_cst , handelt es sich um einen sequenziell konsistenten Acquire-Fence und Release-Fence.
Parameter
| order | - | die von diesem Fence ausgeführte Speicherreihenfolge |
Hinweise
Auf x86 (einschließlich x86-64),
atomic_thread_fence
Funktionen geben keine CPU-Befehle aus und beeinflussen nur die Codebewegung zur Compile-Zeit, außer für
std
::
atomic_thread_fence
(
std::
memory_order_seq_cst
)
.
atomic_thread_fence
erlegt stärkere Synchronisierungsbeschränkungen auf als eine atomare Speicheroperation mit demselben
std::memory_order
. Während eine atomare Store-Release-Operation verhindert, dass alle vorangehenden Lese- und Schreiboperationen über die Store-Release-Operation hinaus verschoben werden, verhindert ein
atomic_thread_fence
mit
std::
memory_order_release
-Reihenfolge, dass alle vorangehenden Lese- und Schreiboperationen über alle nachfolgenden Speicheroperationen hinaus verschoben werden.
Fence-Fence-Synchronisation kann verwendet werden, um einer Sequenz mehrerer entspannter atomarer Operationen Synchronisation hinzuzufügen, zum Beispiel:
// Global std::string computation(int); void print(std::string); std::atomic<int> arr[3] = {-1, -1, -1}; std::string data[1000]; //nicht-atomare Daten // Thread A, berechnet 3 Werte. void ThreadA(int v0, int v1, int v2) { // assert(0 <= v0, v1, v2 < 1000); data[v0] = computation(v0); data[v1] = computation(v1); data[v2] = computation(v2); std::atomic_thread_fence(std::memory_order_release); std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed); std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed); std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed); } // Thread B, gibt zwischen 0 und 3 bereits berechnete Werte aus. void ThreadB() { int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed); int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed); int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_acquire); // v0, v1, v2 könnten sich als -1 herausstellen, einige oder alle davon. // Andernfalls ist es aufgrund der Fences sicher, die nicht-atomaren Daten zu lesen: if (v0 != -1) print(data[v0]); if (v1 != -1) print(data[v1]); if (v2 != -1) print(data[v2]); }
Beispiel
Scannen Sie ein Array von Mailboxen und verarbeiten Sie nur die für uns bestimmten, ohne unnötige Synchronisierung. Dieses Beispiel verwendet Atomic-Fence-Synchronisierung.
const int num_mailboxes = 32; std::atomic<int> mailbox_receiver[num_mailboxes]; std::string mailbox_data[num_mailboxes]; // Die Writer-Threads aktualisieren nicht-atomare gemeinsame Daten // und aktualisieren dann mailbox_receiver[i] wie folgt: mailbox_data[i] = ...; std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release); // Der Reader-Thread muss alle mailbox[i] prüfen, muss aber nur mit einem synchronisieren. for (int i = 0; i < num_mailboxes; ++i) if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) { // Synchronisiere nur mit einem Writer std::atomic_thread_fence(std::memory_order_acquire); // Garantiert, alles zu sehen, was im Writer-Thread // vor dem atomic_store_explicit() ausgeführt wurde do_work(mailbox_data[i]); }
Siehe auch
|
(C++11)
|
definiert Speicherreihenfolge-Einschränkungen für die gegebene atomare Operation
(enum) |
|
(C++11)
|
Barriere zwischen einem Thread und einem Signal-Handler im selben Thread
(function) |
|
C-Dokumentation
für
atomic_thread_fence
|
|