Предположим, что у меня есть свои собственные неподставляемые функции LockMutex и UnlockMutex, которые используют некоторое надлежащее взаимное исключение - такое как повышение - внутри. Как компилятор будет знать для не переупорядочения других операций относительно вызовов к LockMutex и UnlockMutex? Это не может возможно знать, как я реализую эти функции в некоторой другой единице компиляции.
void SomeClass::store(int i)
{
LockMutex(_m);
_field = i; // could the compiler move this around?
UnlockMutex(_m);
}
PS: Каждый, как предполагается, использует экземпляры классов для фиксаторов для гарантии разблокирования. Я пропустил это для упрощения примера.
Возможно, он не знает, как я буду реализовывать эти функции в каком-нибудь другом модуле компиляции.
Это ключ - поскольку компилятор не может знать (в общем) о реализации вызовов функций, он не может переместить хранилище в _field
вне этих вызовов функций.
Обычно, поскольку _field
доступен за пределами SomeClass :: store ()
(он не локальный), компилятор не может знать, было ли оно изменено внешним функция, поэтому она должна выполнять сохранение в _field
между точками последовательности вызовов функций.
Базовая аппаратная платформа может нуждаться в некотором внимании в виде барьеров памяти или очистки кеша, чтобы иметь дело с кэшированием или неупорядоченными операциями, которые происходят в оборудовании. Реализация API мьютексов на платформе при необходимости решит эти проблемы.
Если бы компилятор делал это, это был бы плохой компилятор. ; -)
В общем, компилятор не будет перемещать код, если он не знает с уверенностью, что это не повлияет на поведение во время выполнения.
Вы правы, этот код правильный и безопасный. Я все же придумал "шутку о коде".
pthread_mutex_lock( &mx ) + foo() + pthread_mutex_unlock( &mx );
Как написано, если функции не встроены, компилятор не будет перемещать присвоение переменной, поскольку вызов может не иметь отношения к переменной _field, но он должен сохранять строгий порядок вызовов. Если, однако, компилятор решит встроить вызовы, я думаю, он будет рассматривать их как блоки независимого кода, то есть он будет переупорядочивать инструкции только в том же блоке кода (сама встроенная функция), но не со следующими или предшествующими код (присвоение переменной _field).
Если компилятор не может гарантировать, что вызовы функций не будут иметь побочных эффектов, которые изменят переменные между вызовами, он не может переместить код. Если переменная является локальной переменной, и вы никогда не использовали ссылку или не создавали указатель на нее, компилятор может предположить, что ее перемещение безопасно; Я не знаю.