Ответ Шеффа описывает, как исправить ваш код. Я подумал, что добавлю немного информации о том, что на самом деле происходит в этом случае.
Я скомпилировал ваш код на godbolt , используя уровень оптимизации 1 (-O1
). Ваша функция компилируется так:
func():
cmp BYTE PTR finished[rip], 0
jne .L4
.L5:
jmp .L5
.L4:
mov eax, 0
ret
Итак, что здесь происходит? Во-первых, у нас есть сравнение: cmp BYTE PTR finished[rip], 0
- это проверяет, является ли finished
ложным или нет.
Если это не ложно (иначе true), мы должны выйти из циклана первом запуске. Это достигается с помощью jne .L4
, который j увеличивается, когда n ot e квалифицируется для метки .L4
, где значение i
(0
) равносохраняется в регистре для последующего использования, и функция возвращает.
Если оно равно ложь, однако, мы переходим к
.L5:
jmp .L5
Это безусловный переход к метке.L5
, именно так и происходит сама команда перехода.
Другими словами, поток помещается в бесконечный цикл занятости.
Так почему же это произошло?
Что касается оптимизатора, потоки находятся за пределами его компетенции. Предполагается, что другие потоки не читают и не записывают переменные одновременно (потому что это будет гонка данных UB). Вы должны сказать ему, что он не может оптимизировать доступ. Именно здесь приходит ответ Шеффа. Я не буду его повторять.
Поскольку оптимизатору не сообщают, что переменная finished
может потенциально измениться во время выполнения функции, он видит, что finished
не изменяется самой функцией и предполагает, что она постоянна.
Оптимизированный код обеспечивает два пути кода, которые получатся при вводе функции с постоянным значением bool;либо он запускает цикл бесконечно, либо цикл никогда не запускается.
при -O0
компилятор (как и ожидалось) не оптимизирует тело цикла и его сравнение:
func():
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], 0
.L148:
movzx eax, BYTE PTR finished[rip]
test al, al
jne .L147
add QWORD PTR [rbp-8], 1
jmp .L148
.L147:
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
поэтомуКогда функция неоптимизирована и работает, отсутствие атомарности здесь обычно не является проблемой, потому что код и тип данных просты. Вероятно, худшее, с чем мы могли бы здесь столкнуться, это значение i
, которое на единицу меньше, чем должно .
Более сложная система со структурами данных гораздо более вероятнапривести к повреждению данных или неправильному выполнению.