Ich frage mich, wie std::atomic_ref
effizient (eine std::mutex
pro Objekt) für nichtatomare Objekte implementiert werden kann , da die folgende Eigenschaft ziemlich schwer durchzusetzen scheint:
Atomoperationen, die über eine atomare Referenz auf ein Objekt angewendet werden, sind atomar in Bezug auf atomare Operationen, die über eine andere atomare Referenz angewendet werden, die auf dasselbe Objekt verweist.
Insbesondere der folgende Code:
void set(std::vector<Big> &objs, size_t i, const Big &val) {
std::atomic_ref RefI{objs[i]};
RefI.store(val);
}
Scheint ziemlich schwierig zu implementieren, da das std::atomic_ref
irgendwie jedes Mal das gleiche auswählen müsste std::mutex
(es sei denn, es ist eine große Master-Sperre, die von allen Objekten des gleichen Typs gemeinsam genutzt wird).
Vermisse ich etwas Oder ist jedes Objekt für die Implementierung verantwortlich std::atomic_ref
und daher entweder atomar oder trägt ein std::mutex
?
Antworten:
Die Implementierung ist ziemlich genau die gleiche wie die
std::atomic<T>
selbst. Dies ist kein neues Problem.Siehe Wo ist die Sperre für ein std :: atomic? Eine typische Implementierung
std::atomic
/std::atomic_ref
eine statische Hash - Tabelle von Sperren, durch Adresse indiziert, für nicht-lock freier Objekte. Hash-Kollisionen führen nur zu zusätzlichen Konflikten, nicht zu einem Korrektheitsproblem. (Deadlocks sind immer noch unmöglich; die Locks werden nur von atomaren Funktionen verwendet, die niemals versuchen, 2 gleichzeitig zu nehmen.)In GCC ist dies beispielsweise
std::atomic_ref
nur eine weitere Möglichkeit,__atomic_store
ein Objekt aufzurufen . (Siehe das GCC-Handbuch: Atomic Builtins )Der Compiler weiß, ob er
T
klein genug ist, um sperrenfrei zu sein oder nicht. Wenn nicht, ruft es die libatomische Bibliotheksfunktion auf, die die Sperre verwendet.(Unterhaltsame Tatsache: Das bedeutet, dass es nur funktioniert, wenn das Objekt ausreichend ausgerichtet ist
atomic<T>
. Auf vielen 32-Bit-Plattformen, einschließlich x86, istuint64_t
möglicherweise nur eine 4-Byte-Ausrichtung vorhanden.atomic_ref
Auf einem solchen Objekt wird es kompiliert und ausgeführt, ist jedoch nicht atomar, wenn Der Compiler verwendet ein SSE-8-Byte-Laden / Speichern im 32-Bit-Modus, um es zu implementieren. Glücklicherweise besteht keine Gefahr für Objekte, diealignof(T) == sizeof(T)
wie die meisten primitiven Typen auf 64-Bit-Architekturen vorhanden sind.)quelle
atomic<T>
dass dies auch für nichtatomare Typen erlaubt war (obwohl man sich technisch ein zuordnenmutex
konnte, da es das Objekt besitzt). Danke für die Erklärung, es macht Sinn.Eine Implementierung kann einen Hash basierend auf der Adresse des Objekts verwenden, um zu bestimmen, welche einer Reihe von Sperren während der Ausführung der Operation erfasst werden sollen.
quelle
shared_ptr
Objekten. github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/…