c ++, std :: atomic, was ist std :: memory_order und wie benutzt man sie?

73

Kann jemand erklären, was std::memory_orderim Klartext ist und wie man sie benutzt std::atomic<>?

Ich habe die Referenz und einige Beispiele hier gefunden, verstehe sie aber überhaupt nicht. http://en.cppreference.com/w/cpp/atomic/memory_order

2607
quelle
2
+1 sehr gute Frage. Hoffen wir auf gute Antworten!
Prost und hth. - Alf
1
Ich fand diese (ziemlich dichte) Antwort in der Vergangenheit hilfreich als Einführung in die Speicherreihenfolge.
Luc Danton
Es scheint, dass dieses Thema ziemlich tief gehen kann. Wie zvrba vorgeschlagen hat, kann es als Anfänger wie ich eine gute Idee sein, den Standardwert "sequentiell konsistente Reihenfolge" zu verwenden.
2607
Verwandte: stackoverflow.com/questions/12346487/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Antworten:

25

Kann jemand erklären, was std :: memory_order im Klartext ist,

Die beste Erklärung für "Plain English", die ich für die verschiedenen Speicherreihenfolgen gefunden habe, ist Bartoz Milewskis Artikel über entspannte Atomik: http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/

Und der Follow-up-Beitrag: http://bartoszmilewski.com/2008/12/23/the-inscrutable-c-memory-model/

Beachten Sie jedoch, dass diese Artikel zwar eine gute Einführung sind, jedoch vor dem C ++ 11-Standard liegen und nicht alles enthalten, was Sie wissen müssen, um sie sicher zu verwenden.

und wie man sie mit std :: atomic <> benutzt?

Mein bester Rat an Sie hier ist: Nicht . Entspannte Atomics sind (wahrscheinlich) die schwierigste und gefährlichste Sache in C ++ 11. Halten Sie sich an std::atomic<T>die Standard-Speicherreihenfolge (sequentielle Konsistenz), bis Sie wirklich sicher sind, dass Sie ein Leistungsproblem haben, das mithilfe der entspannten Speicherreihenfolge gelöst werden kann.

Im zweiten oben verlinkten Artikel kommt Bartoz Milewski zu folgendem Schluss:

Ich hatte keine Ahnung, worauf ich mich einließ, als ich versuchte, über schwache C ++ - Atomics nachzudenken. Die Theorie dahinter ist so komplex, dass sie unbrauchbar ist. Es waren drei Personen (Anthony, Hans und ich) und eine Änderung des Standards erforderlich, um den Beweis eines relativ einfachen Algorithmus zu vervollständigen. Stellen Sie sich vor, Sie tun dasselbe für eine Warteschlange ohne Sperren, die auf schwachen Atomen basiert!

je4d
quelle
Danke für deinen Rat. Als Anfänger fand ich das sehr hilfreich.
2607
1
In Jeff Preshings Artikeln, wie diesem über Erwerb / Veröffentlichung , finden Sie hervorragendes Intro-Material, das C ++ 11 beschreibt und Dinge in Bezug auf die Arten der zulässigen / nicht zulässigen Neuordnung des Speichers beschreibt. (zB StoreLoad Nachbestellung ist erlaubt)
Peter Cordes
2
relaxedist viel einfacher zu verstehen: Verwenden Sie es, wenn Sie nur Atomizität und keine Synchronisation benötigen. Beispiel: Für einen einzelnen Atomzähler werden mehrere Threads erhöht, aber das hat keine Bedeutung dafür, ob andere Daten gültig sind.
Peter Cordes
42

Mit den std::memory_orderWerten können Sie feinkörnige Einschränkungen für die Speicherreihenfolge festlegen, die durch Ihre atomaren Operationen bereitgestellt wird. Wenn Sie ändern und Atom-Variablen von mehreren Threads zugegriffen wird , dann die vorbeifahrenden std::memory_orderWerte für Ihren Betrieb können Sie entspannen die Einschränkungen für den Compiler und Prozessor über die Reihenfolge , in der die Operationen auf diesen atomaren Variablen zu anderen Threads sichtbar werden, und die Synchronisation Auswirkungen dieser Operationen auf die nichtatomaren Daten in Ihrer Anwendung.

Die Standardreihenfolge von std::memory_order_seq_cstist die am stärksten eingeschränkte und bietet die "intuitiven" Eigenschaften, die Sie möglicherweise erwarten: Wenn Thread A einige Daten speichert und dann ein atomares Flag mit setzt std::memory_order_seq_cst, kann Thread B sehen, dass das Flag gesetzt ist, wenn er sieht, dass das Flag gesetzt ist Die anderen Werte für die Speicherreihenfolge bieten nicht unbedingt diese Garantie und müssen daher sehr sorgfältig verwendet werden.

Die Grundvoraussetzung lautet: Verwenden Sie nichts anderes als std::memory_order_seq_cst(die Standardeinstellung), es sei denn (a) Sie wissen wirklich wirklich , was Sie tun, und können beweisen, dass die entspannte Verwendung in allen Fällen sicher ist, und (b) Ihr Profiler zeigt, dass die Datenstruktur und Operationen, mit denen Sie die entspannten Bestellungen verwenden möchten, sind ein Engpass.

Mein Buch C ++ Concurrency in Action widmet ein ganzes Kapitel (45 Seiten) den Details des C ++ - Speichermodells, den atomaren Operationen und den std::memory_orderEinschränkungen sowie ein weiteres Kapitel (44 Seiten) der Verwendung atomarer Operationen zur Synchronisation in sperrenfreien Datenstrukturen und die Konsequenzen lockerer Ordnungsbeschränkungen.

Meine Blogeinträge zum Dekker-Algorithmus und zum Peterson-Algorithmus zum gegenseitigen Ausschluss zeigen einige der Probleme.

Anthony Williams
quelle
2
Entspannt ist ziemlich sicher für das, wofür es wirklich benötigt wird - isolierte Werte zu lesen, die keine abhängigen / entsprechenden Werte haben und daher kein Risiko für Bestellprobleme. ZB ein, bool shouldHaltweil ich einen Thread gebeten habe, aufzuhören. Nach meiner Erfahrung ist eine solche Isolation in der normalen Softwareentwicklung nicht selten. Und ich behaupte, dass für den anderen Fall (Abhängigkeiten zwischen mehreren Variablen) eine Sperre fast immer besser ist. Der einzige Weg, wie ich sehe, dass Menschen Schwierigkeiten damit haben, sind ausgefallene atomar verknüpfte Datenstrukturen, auf die man wirklich achten sollte, es sei denn, es besteht ein ernsthafter Bedarf.
VoidStar
In C ++ Concurrency in Action (Zweite Ausgabe) verwenden Sie nach der Einführung std::memory_orderin Abschnitt 5.2.1 viele verschiedene Ordnungen (noch bevor Sie erklären, was sie in Abschnitt 5.3.3 tatsächlich tun), anstatt sich an std::memory_order_seq_cstdie in dieser Antwort vorgeschlagene Reihenfolge zu halten . Bedeutet dies, dass diese Antwort (oder das Buch) falsch ist, oder habe ich etwas falsch verstanden?
Die Beispiele in Abschnitt 5.2 des Buches geben die Speicherreihenfolge an, um zu zeigen, wie Sie dies tun würden und welche Auswahl Sie treffen. Für echten Code sollten Sie sich halten, es std::memory_order_seq_cstsei denn, Sie wissen wirklich, was Sie tun, und es handelt sich um einen nachgewiesenen Leistungsengpass.
Anthony Williams
18

Nein . A „einfache Englisch“ Erklärung nimmt 32 Seiten und kann gefunden werden hier .

Wenn Sie das nicht lesen möchten, können Sie die Speicherreihenfolge vergessen, da auf der von Ihnen verlinkten Seite angegeben wird, dass die Standardeinstellung eine sequentiell konsistente Reihenfolge ist, die die Einstellung "Immer das Vernünftige tun" lautet.

Um eine andere Einstellung zu verwenden, müssen Sie das obige Papier und die darin enthaltenen Beispiele wirklich lesen und verstehen.

zvrba
quelle
5

Kurz gesagt, Ihr Compiler und Ihre CPU können Anweisungen in einer anderen Reihenfolge ausführen, als Sie sie geschrieben haben. Für einen einzelnen Thread ist dies kein Problem, da es korrekt erscheint. Bei mehreren Threads auf mehreren Prozessoren wird dies zu einem Problem. Die Speicherreihenfolge in C ++ schränkt die Funktionen Ihres Compilers / Ihrer CPU ein und behebt solche Probleme.

Wenn Sie sich zum Beispiel meinen Artikel über das Überprüfen von Sperren ansehen, können Sie sehen, wie das Bestellen von Fehlern mit diesem Muster - es wird erwähnt, dass die Reihenfolge des atomaren Speichers verwendet werden kann, um das Problem zu beheben.

Über die Neuordnung selbst können Sie auch eine CPU-Neuordnung in Betracht ziehen - auch hier führt der Compiler möglicherweise auch Neuordnungen durch .

Beachten Sie, dass alle Dokumente zu diesem Thema (einschließlich meiner) von theoretischen Szenarien sprechen. Die gängigsten CPUs wie x86 haben sehr starke Bestellgarantien, so dass viele explizite Ordnungen einfach nicht erforderlich sind. Selbst wenn Sie nicht die richtige C ++ 11-Atomik verwenden, funktioniert Ihr Code wahrscheinlich immer noch.

Wie zvrba erwähnte, ist das Thema eigentlich ziemlich detailliert. Das Linux-Kernel-Dokument zu Speicherbarrieren enthält auch viele detaillierte Informationen.

edA-qa mort-ora-y
quelle