Инструкция по переупорядочению на Intel

Я пытаюсь понять порядок перестановки команд на следующем простом примере:

int a;
int b;

void foo(){
   a = 1;
   b = 1;
}

void bar(){
   while(b == 0) continue;
   assert(a == 1);
}

Известно, что в этом примере утверждение может потерпеть неудачу, если выполняется один поток foo и другой выполняет bar, Но я не понимаю почему. Я обратился к руководству Intel Vol. 3А, 8.2.2 и обнаружил следующее:

Записи в память не переупорядочиваются с другими записями, за следующими исключениями:

- потоковые хранилища (записи), выполняемые с использованием невременных команд перемещения (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS и MOVNTPD); а также

- строковые операции (см. Раздел 8.2.4.1).

Здесь нет строковых операций, так как я не заметил NT переместить инструкции. Итак... Почему возможно изменение порядка записей?

Или память имеет значение в

Пишет в память не переупорядочено

? Итак, когда у нас есть a а также b кеширование и запись происходят не в основную память, а в кеш они могут быть.

2 ответа

Решение

Ваша предпосылка неверна. Только переупорядочение во время компиляции может сломать этот пример на x86 1.

x86 asm хранит релиз-магазины. Они могут фиксировать данные только из буфера хранилища в кэш L1d в программном порядке.

a не может быть в общем состоянии после b=1 виден; это означало бы, что поток работает foo пусть его магазины совершают не в порядке. Это то, что Записывает в память, не переупорядочивается с другими средствами записи, для хранения в кешируемой памяти.

Если он снова находится в общем состоянии после того, как был аннулирован RFO из запущенного потока foo то будет иметь обновленное значение a,


Сноска 1. Конечно, спин-петля оптимизируется в if (b==0) infinite_loop потому что data-race UB позволяет компилятору поднять нагрузку. См. Программирование MCU - оптимизация C++ O2 прерывается во время цикла.

Вы, кажется, спрашиваете о правилах C, предполагая, что код будет наивно / прямо переведен в x86 asm. Вы могли бы получить это с расслабленной атомистикой, но не volatile так как volatile доступ не может быть переупорядочен (во время компиляции) с другими volatile доступ.

Если один поток был запущен foo а другой бежал bar тогда поведение вашей программы будет неопределенным.

Вы не можете одновременно выполнять чтение и запись в неатомарную переменную, такую ​​как int,

Таким образом, запись инструкций допустима в этом случае.

Другие вопросы по тегам