Mein Verständnis von std::memory_order_acquire
und std::memory_order_release
ist wie folgt:Speicher Zäune: acquire/Last und Release/store
Acquire bedeutet, dass keine Speicherzugriffe, die erscheinen nach der acquire Zaun vor dem Zaun neu geordnet werden können .
Veröffentlichung bedeutet, dass kein Speicher, der vor die Freigabe Zaun werden kann, nachdem der Zaun neu geordnet erscheinen zugreift.
Was ich nicht verstehe, ist, warum insbesondere mit der C++ 11 Atomics-Bibliothek der Acquired Fence Ladeoperationen zugeordnet ist, während der Release Fence Speicheroperationen zugeordnet ist.
Um zu klären, die C++ 11 <atomic>
Bibliothek Sie Speicher Zäunen auf zwei Arten angeben kann: entweder Sie einen Zaun als zusätzliches Argument zu einer atomaren Operation angeben können, wie:
x.load(std::memory_order_acquire);
Oder Sie verwenden können std::memory_order_relaxed
und geben Sie den Zaun getrennt, wie:
x.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
Was ich nicht verstehe, ist, die oben genannten Definitionen von acquire gegeben und loslassen, warum C++ 11 assoziieren speziell acquire mit laden und release mit speichern? Ja, ich habe viele der Beispiele gesehen, die zeigen, wie man ein Acquire/Load mit einem release/store zwischen Threads synchronisieren kann, aber im Allgemeinen scheint es, dass Zäune erworben werden (Speicherumordnung nach Anweisung verhindern) und freigeben Zäune (verhindern Speicher-Neuordnung vor Anweisung) ist orthogonal zu der Idee von Lasten und Speichern.
Also, warum zum Beispiel nicht den Compiler lassen Sie mich sagen:
x.store(10, std::memory_order_acquire);
Ich weiß, ich die oben memory_order_relaxed
unter Verwendung erreichen können und dann eine separate atomic_thread_fence(memory_order_acquire)
Aussage, aber wieder, warum kann 't ich verwende Laden direkt mit memory_order_acquire
?
Ein möglicher Anwendungsfall dafür könnte sein, wenn ich, dass einige Speicher sicherstellen will, sagen x = 10
, geschieht vor eine andere Aussage, dass andere Threads möglicherweise beeinflussen ausführt.
In einem typischen lock-free-Algorithmus lesen Sie eine atomare, um zu sehen, ob eine freigegebene Ressource bereit ist für den Verbrauch (bereit zu erwerben), und Sie schreiben eine atomare, um anzuzeigen, dass eine freigegebene Ressource verwendet werden kann (to die Ressource freigeben). Sie möchten nicht, dass die Lesevorgänge der freigegebenen Ressource verschoben werden, bevor das Atomwachen überprüft wird. und Sie möchten nicht, dass die Initialisierung der zu teilenden Ressource nach dem Schreiben des Atoms verschoben wird, um die Freigabe anzuzeigen. –
Im Beispiel ist nur 'atomic_thread_fence (std :: memory_order_acquire)' ein echter Zaun. Siehe ** 1.10: 5 Multi-Thread-Ausführungen und Datenrennen [intro.multithread] ** im Standard, der (unter Angabe des Entwurfs n3797) lautet _ "Ein Synchronisationsvorgang ohne einen zugeordneten Speicherplatz ist ein Zaun und kann entweder ein einen Zaun, einen Freisetzungszaun oder beides, einen Acquire- und einen Release-Zaun. "_ Im Gegensatz dazu ist" x.load (std :: memory_order_acquire) "eine _atomare Operation_, die eine _acquire_ Operation an" x "ausführt, es wäre eine _synchronisation operation_, wenn der Wert einem Speicher _release_ in x entspricht. – amdn
In der Einleitung beschränkt der Standard (Entwurf n3797) die Übernahmevorgänge nicht auf Lasten und gibt Vorgänge an Speicher frei. Das ist bedauerlich. Sie müssen zu Klausel ** 29.3: 1 Reihenfolge und Konsistenz [atomics.order] ** gehen, um _ "memory_order_acquire, memory_order_acq_rel und memory_order_seq_cst zu finden: eine Ladeoperation führt eine Erfassungsoperation an dem betroffenen Speicherort aus" _ und _ "memory_order_release , memory_order_acq_rel, und memory_order_seq_cst: Eine Speicheroperation führt eine Freigabeoperation an dem betroffenen Speicherort aus. _ – amdn