Фраза «сильно случается раньше» используется несколько раз в проекте стандарта C ++.
Например: Завершение [basic.start.term] / 5
Если завершение инициализации объекта со статической продолжительностью хранения сильно происходит до вызова std :: atexit (см. [Support.start.term]), вызов функции передается в std :: atexit последовательность перед вызовом деструктора для объекта. Если вызов std :: atexit сильно происходит до завершения инициализации объекта со статической продолжительностью хранения, то вызов деструктора для объекта упорядочивается до того, как вызов функции передается в std :: atexit. , Если вызов std :: atexit сильно происходит перед другим вызовом std :: atexit, то вызов функции, переданной второму вызову std :: atexit, упорядочивается до вызова функции, переданной первый вызов std :: atexit.
И определено в гонках данных [intro.races] / 12
Оценка A сильно случается перед оценкой D, если либо
(12.1) A секвенируется перед D, или
(12.2) A синхронизируется с D, и A и D являются последовательно согласованными атомарными операциями ([atomics.order]), или
(12.3) существуют оценки B и C такие, что A секвенируется перед B, B просто происходит перед C, а C секвенируется перед D, или
(12.4) существует оценка B такая, что A сильно случается до B, а B сильно предшествует D.
[Примечание: неофициально, если A сильно случается до B, то A, кажется, оценивается перед B во всех контекстах. Сильно случается до того, как исключаются операции потребления. - конец примечания]
Почему было «сильно случается прежде» введено? Интуитивно понятно, в чем его отличие и связь с «случается раньше»?
Что означает «А, по-видимому, оценивается перед В во всех контекстах» в примечании?
(Примечание: мотивация для этого вопроса - комментарии Питера Кордеса под этим ответом .)
Дополнительный проект стандартной цитаты (спасибо Peter Cordes)
Порядок и последовательность [atomics.order] / 4
Для всех операций memory_order :: seq_cst, включая заборы, существует один общий порядок S, который удовлетворяет следующим ограничениям. Во-первых, если A и B являются операциями memory_order :: seq_cst и A сильно предшествует B, то A предшествует B в S. Во-вторых, для каждой пары атомарных операций A и B над объектом M, где A упорядочено по когерентности перед B следующие S должны выполнить следующие четыре условия:
(4.1) если A и B являются обеими операциями memory_order :: seq_cst, то A предшествует B в S; а также
(4.2) если A является операцией memory_order :: seq_cst и B происходит перед забором памяти memory_order :: seq_cst Y, то A предшествует Y в S; а также
(4.3) если ограничение memory_order :: seq_cst X происходит до того, как A и B является операцией memory_order :: seq_cst, то X предшествует B в S; а также
(4.4) если ограничение memory_order :: seq_cst X происходит до A и B происходит до забора memory_order :: seq_cst Y, то X предшествует Y в S.
atexit()
в одном потоке и exit()
в другом, инициализаторам недостаточно переносить только зависимость, основанную на потреблении, только потому, что результаты тогда отличаются от того, exit()
был ли вызван тем же потоком. Мой более старый ответ касался этой разницы.
exit()
. Любой поток может убить всю программу, выйдя из системы, или основной поток может выйти, return
-ing. Это приводит к вызову atexit()
обработчиков и смерти всех потоков, что бы они ни делали.
seq_cst
в Atomics 31.4 Порядок и последовательность: 4 . Этого нет в стандарте C ++ 17 n4659 , где 32.4-3 определяют существование единого общего порядка операций seq_cst, соответствующих порядку «происходит раньше» и порядкам модификации для всех затронутых местоположений ; «сильно» был добавлен в более поздний проект.