Wyrażenie „zdecydowanie zdarza się wcześniej” jest używane kilkakrotnie w standardowym projekcie C ++.
Na przykład: Zakończenie [basic.start.term] / 5
Jeśli zakończenie inicjalizacji obiektu o czasie przechowywania statycznym nastąpi zdecydowanie przed wywołaniem std :: atexit (patrz [support.start.term]), wywołanie funkcji przekazane do std :: atexit jest sekwencjonowany przed wywołaniem obiektu destruktora dla obiektu. Jeśli wywołanie std :: atexit wystąpi zdecydowanie przed zakończeniem inicjalizacji obiektu o statycznym czasie przechowywania, wywołanie obiektu destruktora dla obiektu jest sekwencjonowane przed wywołaniem funkcji std :: atexit . Jeśli wywołanie std :: atexit wystąpi zdecydowanie przed kolejnym wywołaniem std :: atexit, wywołanie funkcji przekazanej do drugiego wywołania std :: atexit jest sekwencjonowane przed wywołaniem funkcji pierwsze wywołanie std :: atexit.
I zdefiniowane w Wyścigi danych [intro.races] / 12
Ocena Zdecydowanie występuje przed oceną D, jeśli również
(12.1) A jest sekwencjonowane przed D, lub
(12.2) A synchronizuje się z D, a oba A i D są sekwencyjnie spójnymi operacjami atomowymi ([atomics.order]) lub
(12.3) istnieją oceny B i C takie, że A jest sekwencjonowane przed B, B po prostu dzieje się przed C, a C jest sekwencjonowane przed D, lub
(12.4) istnieje ocena B taka, że A dzieje się zdecydowanie przed B, a B występuje zdecydowanie przed D.
[Uwaga: Nieoficjalnie, jeśli A zdarza się zdecydowanie przed B, to A wydaje się być oceniane przed B we wszystkich kontekstach. Zdecydowanie dzieje się przed wykluczeniem operacji konsumpcji. - uwaga końcowa]
Dlaczego wprowadzono „zdecydowanie wcześniej”? Intuicyjnie, jaka jest jego różnica i związek z „dzieje się wcześniej”?
Co oznacza „A wydaje się być oceniane przed B we wszystkich kontekstach” w notatce?
(Uwaga: motywem tego pytania są komentarze Petera Cordesa pod tą odpowiedzią ).
Dodatkowy projekt standardowej wyceny (dzięki Peter Cordes)
Porządek i spójność [atomics.order] / 4
Istnieje jedna suma S dla wszystkich operacji memory_order :: seq_cst, w tym ogrodzeń, która spełnia następujące ograniczenia. Po pierwsze, jeśli A i B są operacjami memory_order :: seq_cst, a A zdarza się silnie przed B, to A poprzedza B w S. Po drugie, dla każdej pary operacji atomowych A i B na obiekcie M, gdzie A jest uporządkowaną spójnością przed B S musi spełnić następujące cztery warunki:
(4.1) jeśli A i B są operacjami memory_order :: seq_cst, to A poprzedza B w S; i
(4.2) jeśli A jest operacją memory_order :: seq_cst, a B dzieje się przed ogrodzeniem Y kolejki memory_order :: seq_cst, to A poprzedza Y w S; i
(4.3) jeśli ogrodzenie memory_order :: seq_cst X nastąpi przed A, a B jest operacją memory_order :: seq_cst, to X poprzedza B w S; i
(4.4) jeśli X_pamięci :: seq_cst ogrodzenie X nastąpi przed A, a B ma miejsce przed X_pamięci :: seq_cst ogrodzenie Y, to X poprzedza Y w S.
seq_cst
w Atomics 31.4. Porządek i spójność: 4 . Nie ma tego w standardzie C ++ 17 n4659 , w którym 32.4 - 3 definiuje istnienie pojedynczej całkowitej kolejności operacji seq_cst zgodnej z kolejnością „zamówień sprzed” i zleceniami modyfikacji dla wszystkich dotkniętych lokalizacji ; „zdecydowanie” dodano w późniejszym szkicu.atexit()
w jednym wątku, aexit()
w drugim, inicjalizatory nie mogą przenosić tylko zależności zależnej od zużycia tylko dlatego, że wyniki różnią się od tego, czyexit()
wywołano go przez ten sam wątek. Moja starsza odpowiedź dotyczyła tej różnicy.exit()
. Dowolny wątek może zabić cały program, wychodząc lub główny wątek może wyjść przezreturn
-ing. Powoduje to przywołanie przewodnikówatexit()
i śmierć wszystkich wątków, bez względu na to, co robią.Odpowiedzi:
Przygotuj się również na „po prostu zdarza się wcześniej”! Spójrz na tę bieżącą migawkę cppref https://en.cppreference.com/w/cpp/atomic/memory_order
Wydaje się, że w C ++ 20 dodano „po prostu zdarza się wcześniej”.
Zatem Simply-HB i HB są takie same, z wyjątkiem tego, jak radzą sobie z operacjami konsumpcji. Zobacz HB
Czym różnią się pod względem konsumpcji? Patrz Inter-Thread-HB
Operacja, która jest uporządkowana zależnie (tj. Używa wydania / konsumpcji) to HB, ale niekoniecznie Simply-HB.
Spożywanie jest bardziej relaksujące niż nabywanie, więc jeśli dobrze rozumiem, HB jest bardziej zrelaksowany niż Simply-HB.
Tak więc operacja wydania / konsumpcji nie może być silnie HB.
Zwolnienie / przejęcie może być HB i Simply-HB (ponieważ zwolnienie / przejęcie synchronizuje się z), ale niekoniecznie jest silnie HB. Ponieważ Strong-HB wyraźnie mówi, że A musi zsynchronizować się z B AND być operacją sekwencyjnie spójną.
Wszystkie konteksty: wszystkie wątki / wszystkie procesory widzą (lub „w końcu się zgodzą”) w tej samej kolejności. Jest to gwarancja spójności sekwencyjnej - globalnej kolejności modyfikacji wszystkich zmiennych. Łańcuchy pobierania / zwalniania gwarantują jedynie postrzeganą kolejność modyfikacji dla wątków uczestniczących w łańcuchu. Wątki poza łańcuchem teoretycznie mogą widzieć inną kolejność.
Nie wiem, dlaczego wprowadzono Strong-HB i Simply-HB. Może pomóc wyjaśnić, jak działać wokół konsumpcji? Silnie-HB ma ładne właściwości - jeśli jeden wątek obserwuje Zdecydowanie dzieje się przed B, wie, że wszystkie wątki będą obserwować to samo.
Historia konsumpcji:
Paul E. McKenney jest odpowiedzialny za konsumpcję w standardach C i C ++. Consume gwarantuje uporządkowanie między przypisaniem wskaźnika a pamięcią, na którą wskazuje. Został wynaleziony z powodu DEC Alpha. DEC Alpha mógł spekulacyjnie wyłuskać wskaźnik, dlatego też miał ogrodzenie pamięci, aby temu zapobiec. DEC Alpha nie jest już produkowany i żaden procesor nie ma dzisiaj takiego zachowania. Spożywać ma być bardzo zrelaksowany.
źródło
mo_consume
ma na celu skorzystanie z porządkowania zależności danych na rzeczywistych procesorach i sformalizowanie, że kompilator nie może przerwać zależności danych za pomocą przewidywania gałęzi. np.int *p = load();
tmp = *p;
mógłby zostać zepsuty przez wprowadzenie kompilatora,if(p==known_address) tmp = *known_address; else tmp=*p;
gdyby miał jakiś powód, aby oczekiwać, że pewna wartość wskaźnika będzie wspólna. Jest to legalne dla zrelaksowanego, ale nie konsumpcyjnego.