Der Ausdruck "passiert stark vor" wird im C ++ - Entwurfsstandard mehrmals verwendet.
Zum Beispiel: Kündigung [basic.start.term] / 5
Wenn der Abschluss der Initialisierung eines Objekts mit statischer Speicherdauer stark vor einem Aufruf von std :: atexit erfolgt (siehe [support.start.term]), wird der Aufruf der Funktion an std :: atexit übergeben wird vor dem Aufruf des Destruktors für das Objekt sequenziert. Wenn ein Aufruf von std :: atexit stark vor Abschluss der Initialisierung eines Objekts mit statischer Speicherdauer erfolgt, wird der Aufruf des Destruktors für das Objekt vor dem Aufruf der an std :: atexit übergebenen Funktion sequenziert . Wenn ein Aufruf von std :: atexit stark vor einem weiteren Aufruf von std :: atexit erfolgt, wird der Aufruf der an den zweiten std :: atexit-Aufruf übergebenen Funktion vor dem Aufruf der an den übergebenen Funktion sequenziert erster std :: atexit Aufruf.
Und definiert in Daten Rennen [intro.races] / 12
Eine Bewertung A erfolgt stark vor einer Bewertung D, wenn auch nicht
(12.1) A wird vor D oder sequenziert
(12.2) A synchronisiert mit D und sowohl A als auch D sind sequentiell konsistente atomare Operationen ([atomics.order]) oder
(12.3) Es gibt Bewertungen B und C, so dass A vor B sequenziert wird, B einfach vor C erfolgt und C vor D sequenziert wird, oder
(12.4) Es gibt eine Bewertung B, so dass A stark vor B und B stark vor D auftritt.
[Hinweis: Wenn A informell stark vor B auftritt, scheint A in allen Kontexten vor B bewertet zu werden. Tritt stark auf, bevor Verbrauchsvorgänge ausgeschlossen werden. - Endnote]
Warum wurde "stark passiert vorher" eingeführt? Was ist intuitiv der Unterschied und die Beziehung zu "passiert vorher"?
Was bedeutet das "A scheint in allen Kontexten vor B bewertet zu werden" in der Notiz?
(Hinweis: Die Motivation für diese Frage sind die Kommentare von Peter Cordes unter dieser Antwort .)
Zusätzlicher Entwurf eines Standardzitats (danke an Peter Cordes)
Ordnung und Konsistenz [atomics.order] / 4
Für alle Operationen memory_order :: seq_cst, einschließlich Zäune, gibt es eine einzige Gesamtreihenfolge S, die die folgenden Einschränkungen erfüllt. Erstens, wenn A und B memory_order :: seq_cst-Operationen sind und A stark vor B auftritt, dann steht A in S vor B. Zweitens für jedes Paar atomarer Operationen A und B an einem Objekt M, bei dem A kohärent geordnet ist vor B müssen die folgenden vier Bedingungen von S erfüllt sein:
(4.1) Wenn A und B beide Operationen memory_order :: seq_cst sind, steht A in S vor B; und
(4.2) Wenn A eine Operation memory_order :: seq_cst ist und B vor einem Zaun Y von memory_order :: seq_cst auftritt, steht A in S vor Y; und
(4.3) Wenn ein memory_order :: seq_cst-Zaun X vor A auftritt und B eine memory_order :: seq_cst-Operation ist, steht X in S vor B; und
(4.4) Wenn ein memory_order :: seq_cst-Zaun X vor A und B vor einem memory_order :: seq_cst-Zaun Y auftritt, steht X in S vor Y.
atexit()
einen Thread und einen exit()
anderen aufruft , reicht es für Initialisierer nicht aus, nur eine verbrauchsabhängige Abhängigkeit zu tragen, da sich die Ergebnisse von denen unterscheiden, exit()
die von demselben Thread aufgerufen wurden. Eine ältere Antwort von mir betraf diesen Unterschied.
exit()
. Jeder Thread kann das gesamte Programm durch Beenden beenden, oder der Hauptthread kann durch Beenden beendet werden return
. Dies führt zum Aufruf von atexit()
Handlern und zum Tod aller Threads, was auch immer sie taten.
seq_cst
, die in Atomics 31.4 Reihenfolge und Konsistenz gilt: 4 . Dies ist nicht im C ++ 17 n4659- Standard enthalten, in dem 32.4 - 3 das Vorhandensein einer einzelnen Gesamtreihenfolge von seq_cst-Operationen definiert, die mit der Reihenfolge "Vorher passiert" und den Änderungsreihenfolgen für alle betroffenen Standorte übereinstimmt . Das "stark" wurde in einem späteren Entwurf hinzugefügt.