Відповідь Шеффа описує, як виправити код. Я думав, що додам трохи інформації про те, що насправді відбувається в цій справі.
Я склав ваш код на 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
є помилковим чи ні.
Якщо це НЕ брехня (ака правда) , ми повинні вийти з циклу при першому запуску. Це досягнутоjne .L4
що j umps, коли n ot e qual позначає, .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
що воно відключається від того, яким воно має бути.
Складніша система з структурами даних набагато частіше спричинить пошкодження даних або неправильне виконання.