Câu trả lời của Scheff mô tả cách sửa mã của bạn. Tôi nghĩ rằng tôi sẽ thêm một chút thông tin về những gì đang thực sự xảy ra trong trường hợp này.
Tôi đã biên dịch mã của bạn tại godbolt bằng cách sử dụng tối ưu hóa mức 1 ( -O1
). Hàm của bạn biên dịch như vậy:
func():
cmp BYTE PTR finished[rip], 0
jne .L4
.L5:
jmp .L5
.L4:
mov eax, 0
ret
Vậy thì chuyện gì đã xảy ra ở đây? Đầu tiên, chúng tôi có một so sánh: cmp BYTE PTR finished[rip], 0
- kiểm tra này để xem liệu finished
có sai hay không.
Nếu nó không sai (aka đúng), chúng ta nên thoát khỏi vòng lặp trong lần chạy đầu tiên. Đây thực hiện bằng cách jne .L4
đó j umps khi n ot e qual để nhãn .L4
trong đó giá trị của i
( 0
) được lưu trữ trong một thanh ghi để sử dụng sau và trở về chức năng.
Nếu đó là sai, tuy nhiên, chúng tôi chuyển đến
.L5:
jmp .L5
Đây là một bước nhảy vô điều kiện, để gắn nhãn .L5
mà chính là lệnh nhảy.
Nói cách khác, chuỗi được đưa vào một vòng lặp bận rộn vô hạn.
Vậy tại sao điều này đã xảy ra?
Theo như trình tối ưu hóa có liên quan, các chủ đề nằm ngoài phạm vi của nó. Nó giả định các luồng khác không đọc hoặc ghi các biến đồng thời (vì đó sẽ là cuộc đua dữ liệu UB). Bạn cần nói với nó rằng nó không thể tối ưu hóa truy cập đi. Đây là lúc câu trả lời của Scheff đến. Tôi sẽ không nhắc lại anh ta.
Bởi vì trình tối ưu hóa không được thông báo rằng finished
biến có thể có khả năng thay đổi trong quá trình thực thi hàm, nó thấy rằng finished
nó không bị sửa đổi bởi chính hàm đó và cho rằng nó là hằng số.
Mã được tối ưu hóa cung cấp hai đường dẫn mã sẽ dẫn đến việc nhập hàm với giá trị bool không đổi; hoặc nó chạy vòng lặp vô hạn, hoặc vòng lặp không bao giờ chạy.
tại -O0
trình biên dịch (như mong đợi) không tối ưu hóa thân vòng lặp và so sánh đi:
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
do đó, chức năng, khi không được tối ưu hóa hoạt động, việc thiếu tính nguyên tử ở đây thường không phải là vấn đề, bởi vì mã và kiểu dữ liệu là đơn giản. Có lẽ điều tồi tệ nhất chúng ta có thể gặp phải ở đây là giá trị của i
nó bị giảm đi so với những gì nó nên có.
Một hệ thống phức tạp hơn với cấu trúc dữ liệu có nhiều khả năng dẫn đến dữ liệu bị hỏng hoặc thực thi không đúng.