Стандарт C определяет термин, называемый наблюдаемое поведение .Это означает, что как минимум компилятор / система имеет несколько ограничений: ему не разрешается переупорядочивать выражения, содержащие volatile
-качественные операнды, а также не разрешается переупорядочивать ввод / вывод.
Помимо этих особых случаев, все является честной игрой.Он может выполнить y перед x, он может выполнить их параллельно.Это может оптимизировать весь код, поскольку в коде нет видимых побочных эффектов.И так далее.
Обратите внимание, что потокобезопасность и порядок выполнения - это разные вещи.Потоки создаются явно программистом / библиотеками.Переключение контекста может прервать любую переменную доступа, которая не является атомарной.Это еще одна проблема, и решение заключается в использовании мьютекса, квалификатора _Atomic
или аналогичных механизмов защиты.
Если порядок имеет значение, вам следует volatile
-квалифицировать переменные.В этом случае языком предоставляются следующие гарантии:
C17 5.1.2.3 § 6 (определение наблюдаемого поведения):
Доступ к изменчивым объектам оценивается строго в соответствии справилам абстрактной машины.
C17 5.1.2.3 § 4:
В абстрактной машине все выражения оцениваются в соответствии с семантикой.
Где«семантика» - это почти весь стандарт, например, часть, которая указывает, что ;
состоит из точки последовательности.(В этом случае C17 6.7.6 «Конец полного декларатора является точкой последовательности.» Термин «секвенированный до» определен в C17 5.1.2.3 §3).
Итак, с учетом этого:
volatile int x = 1;
volatile int y = 1;
тогда порядок инициализации гарантированно будет равен x перед y, так как ;
в первой строке гарантирует порядок упорядочения, а volatile
гарантирует, что программа строго следует порядку оценки, указанному в стандарте.
Теперь, как это происходит в реальном мире, volatile
не гарантирует барьеры памяти во многих реализациях компиляторов для многоядерных систем.Эти реализации не соответствуют.
Оппортунистические компиляторы могут утверждать, что программист должен использовать системные барьеры памяти, чтобы гарантировать порядок выполнения.Но в случае volatile
это не так, как доказано выше.Они просто хотят уклониться от ответственности и передать ее программистам.Стандарт C не заботится о том, что процессор имеет 57 ядер, предсказание ветвлений и конвейеризацию команд.