

아무리 생각해봐도 r1과 r2 모두 0이 나올 수 있는 경우의 수가 없다.
어떻게 0이 되어서 무한루프를 빠져나올 수 있었을까?
- 멀티스레딩과 동시성
: 멀티스레드 프로그램에서 여러 스레드가 동시에 실행되며, 이들의 실행 순서는 운영 체제의 스케줄러에 의해 결정된다. 이로 인해 스레드의 작업 실행 순서는 예측 불가능하며 매번 다를 수 있다.
- 순서 교환(Out-of-order execution)
: 현대 CPU는 성능 최적화를 위해 명령어를 프로그램 코드에 명시된 순서와 다르게 실행할 수 있다. 이는 멀티스레드 환경에서 예측하기 어려운 결과를 초래할 수 있다.
💡 r1 == 0 && r2 == 0이 가능한 시나리오:
이 시나리오에서는 Thread_1의 y = 1;과 Thread_2의 x = 1;이 각각 r1 = x;와 r2 = y;보다 나중에 실행된다. 이는 CPU의 순서 교환 또는 스레드 스케줄링에 의해 발생할 수 있다.
이러한 현상을 방지하기 위해서는 추가적인 동기화 메커니즘을 사용해야한다. (메모리 배리어)
- Full Memory Barrier (ASM MFENCE, C# Thread.MemoryBarrier)
: Store/Load 둘 다 막는다.
- Store Memory Barrier (ASM SFENCE)
: Store만 막는다.
- Load Memory Barrier (ASM LFENCE)
: Load만 막는다.
ㄴ 보통은 위 예시처럼 Full Memory Barrier를 많이 사용한다.
멀티스레드 환경에서, 하나의 스레드에 의해 수행된 변경사항이 다른 스레드에 즉각적으로 보이지 않을 수 있다. 이는 CPU 캐시, 컴파일러 최적화, 시스템 아키텍처 등 다양한 요인 때문이다.
(앞서 배웠던 volatile도 가시성의 기능을 했다.)
