Я реализовал спин-блокировку в NASM-64 для Windows.Я использую спин-блокировку для блокировки буфера общей памяти, чтобы каждое ядро записывало в общий буфер по одному ядру за раз (ядро 0 сначала, ядро 1 секунда, ядро 2 третье и т. Д.). Насколько я знаюмьютекс или семафор не позволят мне выполнять буферизацию в основном порядке, и спин-блокировка предпочтительнее, потому что она не использует вызов ОС.
Вот этот раздел кода.Это не полный пример, потому что проблема в этом небольшом разделе гораздо большей программы сборки.Я использовал cmpxchg для атомарности.
При входе в этот раздел rax содержит номер ядра, а rbx - переменную памяти spinlock_core, которая устанавливается на ноль (первое ядро) при входе в этот раздел.После того как каждое ядро закончено, spinlock_core увеличивается до следующего номера ядра.
mov rdi,Test_Array
movq rbx,xmm11
mov [rdi+rax],rbx ; rax contains the core number offset (0, 8, 16, 24)
push rax
; Spin Lock
spin_lock_01:
lock cmpxchg [spinlock_core],rax ; spinlock_core is set to zero on first entry
jnz spin_lock_01
; To test the result:
mov rdi,Test_Array
mov [rdi+rax+32],rax
jmp out_of_here
Результаты этого теста находятся в Test_Array, который заполняется количеством байтов для записи для каждого ядра.По возвращении он содержит:
40, 40, 40, 16, 0, 8, 16, 24
, показывающий, что ядро 0-2 имеет 40 байтов для записи, а ядро 3 имеет 16 байтов для записи.Однако последние четыре элемента Test_Array содержат смещение ядра для каждого из четырех ядер.Если спин-блокировка работала правильно (cmpxchg rax, rbx), последние четыре элемента должны содержать ноль, показывая, что пропущено только первое ядро.Но это показывает, что все четыре ядра были пропущены.
Я предполагаю, что мой cmpxchg не является атомарным, и поэтому другие ядра просачиваются сквозь него - они должны быть разрешены только при увеличении spinlock_core до следующего ядра, но этого не происходит до того, как мы выйдем с jmpотсюда.Согласно документам, cmpxchg должен предшествовать префикс «lock», как в блокировке cmpxchg rax, rbx, но когда я это делаю, ассемблер NASM говорит «предупреждение: инструкция не блокируется [-w + lock]».Сайт Феликса Клутье говорит, что префикс блокировки необходим только в том случае, если задействован операнд памяти, но когда я пишу «cmpxchg rax, [spinlock_core]», я получаю «недопустимую комбинацию кодов операций и операндов».
Подводя итог, я могу задать следующие вопросы: почему cmpxchg не является атомарным, как написано выше, и почему ассемблер NASM не позволяет использовать префикс блокировки?
Существует множество подробных сообщений о переполнении стека и в других местах по вопросу атомарности, но я не нашел ни одного, который бы касался этой конкретной проблемы.
Спасибо за любую помощь.