Jawaban Scheff menjelaskan cara memperbaiki kode Anda. Saya pikir saya akan menambahkan sedikit informasi tentang apa yang sebenarnya terjadi dalam kasus ini.
Saya mengkompilasi kode Anda di godbolt menggunakan optimasi level 1 ( -O1
). Fungsi Anda mengkompilasi seperti:
func():
cmp BYTE PTR finished[rip], 0
jne .L4
.L5:
jmp .L5
.L4:
mov eax, 0
ret
Jadi, apa yang terjadi di sini? Pertama, kami memiliki perbandingan: cmp BYTE PTR finished[rip], 0
- ini memeriksa untuk melihat apakah finished
salah atau tidak.
Jika tidak salah (alias benar) kita harus keluar dari loop pada proses pertama. Hal ini dicapai dengan jne .L4
yang j umps ketika n ot e qual ke label .L4
dimana nilai i
( 0
) disimpan dalam register untuk digunakan dan fungsi kembali.
Jika adalah palsu namun, kami pindah ke
.L5:
jmp .L5
Ini adalah lompatan tanpa syarat, untuk memberi label .L5
yang kebetulan merupakan perintah lompatan itu sendiri.
Dengan kata lain, utas dimasukkan ke dalam loop sibuk tanpa batas.
Jadi mengapa ini terjadi?
Sejauh menyangkut optimiser, utas berada di luar ruang lingkupnya. Ini mengasumsikan utas lainnya tidak membaca atau menulis variabel secara bersamaan (karena itu akan menjadi data-ras UB). Anda perlu mengatakan bahwa itu tidak dapat mengoptimalkan akses jauh. Di sinilah jawaban Scheff masuk. Saya tidak akan repot-repot mengulanginya.
Karena pengoptimal tidak diberitahu bahwa finished
variabel berpotensi berubah selama eksekusi fungsi, ia melihat bahwa finished
itu tidak dimodifikasi oleh fungsi itu sendiri dan mengasumsikan bahwa itu konstan.
Kode yang dioptimalkan menyediakan dua jalur kode yang akan dihasilkan dari memasukkan fungsi dengan nilai bool konstan; baik itu menjalankan loop secara tak terbatas, atau loop tidak pernah berjalan.
di -O0
compiler (seperti yang diharapkan) tidak mengoptimalkan loop body dan perbandingannya:
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
oleh karena itu fungsinya, ketika tidak dioptimalkan berhasil, kurangnya atomisitas di sini biasanya tidak menjadi masalah, karena kode dan tipe data sederhana. Mungkin yang terburuk kita bisa lari ke sini adalah nilai i
yang off per satu untuk apa yang harus menjadi.
Sistem yang lebih kompleks dengan struktur data jauh lebih mungkin menghasilkan data yang rusak, atau eksekusi yang tidak tepat.