Инструкция pause в x86

Я пытаюсь создать тупую версию блокировки спина. Просматривая Интернет, я столкнулся с инструкцией по сборке в x86, которая используется, чтобы дать подсказку процессору, который в настоящий момент работает в этом процессоре. В руководстве Intel и другой информации указано, что

The processor uses this hint
to avoid the memory order violation in most situations, which greatly improves
processor performance. For this reason, it is recommended that a PAUSE instruction
be placed in all spin-wait loops. The documentation also mentions that 
"wait(some delay)" is the pseudo implementation of the instruction. 

Последняя строка вышеприведенного абзаца интуитивно понятна. Если мне не удастся схватить замок, я должен подождать некоторое время, прежде чем снова схватить замок.

Однако, что мы имеем в виду под нарушением порядка памяти в случае блокировки спина??? "Нарушение порядка памяти" означает неправильную умозрительную загрузку/сохранение инструкций после блокировки отпирания??

FYI, вопрос о спин-блокировке задан перед переполнением стека, но вопрос о нарушении порядка памяти остается без ответа... по крайней мере для моего понимания

Ответ 1

Представьте себе, как процессор выполнит типичный цикл ожидания ожидания:

1 Spin_Lock:
2    CMP lockvar, 0   ; Check if lock is free
3    JE Get_Lock
4    JMP Spin_Lock
5 Get_Lock:

После нескольких итераций предсказатель ветвления предскажет, что условная ветвь (3) никогда не будет принята, и трубопровод будет заполняться инструкциями CMP (2). Это продолжается до тех пор, пока, наконец, другой процессор не будет записывать нуль в lockvar. На этом этапе у нас есть конвейер, полный спекулятивных (т.е. Еще не выполненных) инструкций CMP, некоторые из которых уже считывают lockvar и сообщают (неверный) ненулевой результат в следующую условную ветвь (3) (также спекулятивную). Это происходит при нарушении порядка памяти. Всякий раз, когда процессор "видит" внешнюю запись (запись от другого процессора), он ищет в своем конвейере инструкции, которые спекулятивно обращались к одному и тому же месту памяти и еще не зафиксировали. Если какие-либо такие инструкции найдены, то спекулятивное состояние процессора недействительно и стирается с помощью флеш-конвейера.

К сожалению, этот сценарий будет (очень вероятно) повторяться каждый раз, когда процессор ожидает открутить блокировку и сделает эти блокировки намного медленнее, чем они должны быть.

Введите инструкцию PAUSE:

1 Spin_Lock:
2    CMP lockvar, 0   ; Check if lock is free
3    JE Get_Lock
4    PAUSE            ; Wait for memory pipeline to become empty
5    JMP Spin_Lock
6 Get_Lock:

Инструкция PAUSE будет "де-конвейерно" считывать память, так что конвейер не заполняется спекулятивными инструкциями CMP (2), как в первом примере. (Т.е. он может блокировать конвейер до тех пор, пока не будут зафиксированы все старые команды памяти.) Поскольку инструкции CMP (2) выполняются последовательно, маловероятно (т.е. временное окно намного короче), что внешняя запись происходит после того, как инструкция CMP (2) читается lockvar, но до выполнения CMP.

Конечно, "де-конвейерная обработка" также будет тратить меньше энергии на спин-замок, а в случае гиперпотока это не будет тратить ресурсы, которые другая нить могла бы использовать лучше. С другой стороны, все еще существует неправильное предсказание ветвления, ожидающее появления перед каждым выходом цикла. Документация Intel не предполагает, что PAUSE устраняет этот поток потока, но кто знает...