Scheff의 답변은 코드를 수정하는 방법을 설명합니다. 나는이 경우 실제로 일어나는 일에 대해 약간의 정보를 추가 할 것이라고 생각했습니다.
최적화 수준 1 ( )을 사용하여 godbolt 에서 코드를 컴파일했습니다 -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 개의 umps N OT 전자 라벨 QUAL .L4
의 값이 여기서 i
( 0
) 이상 사용 함수가 리턴하는 레지스터에 저장된다.
이 경우 이다 그러나 거짓, 우리는로 이동
.L5:
jmp .L5
이것은 .L5
점프 명령 자체 가되는 무조건 점프 입니다.
즉, 스레드는 무한 사용중 루프에 놓입니다.
왜 이런 일이 일어 났습니까?
옵티 마이저와 관련하여 스레드는 그 범위를 벗어납니다. 다른 스레드가 변수를 동시에 읽거나 쓰지 않는다고 가정합니다 (데이터 레이스 UB이기 때문에). 액세스를 최적화 할 수 없다는 것을 알려야합니다. 이것은 Scheff의 대답이 나오는 곳입니다. 나는 그를 반복하지 않을 것입니다.
옵티마이 저는 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
가 하나가되어 있어야하는 것입니다.
데이터 구조가있는보다 복잡한 시스템은 데이터가 손상되거나 실행이 잘못 될 가능성이 훨씬 높습니다.