Preshing 블로그 정리
Reordering의 사례 소개
먼저 다음 코드를 살펴보자

해당 코드 대로라면 A가 먼저 연산되고, B가 계산될 것으로 예상되지만 최적화 옵션을 가질 경우, 예상을 어긋나는 방향으로 동작하게 된다.
어셈블리 코드로 풀어서 본다면 예상되는 코드는 다음과 같을 것이다. (최적화 않은 경우)

C로 구현된 코드와 같이 B를 eax 범용 레지스터로 옮기고 여기에 1을 더한 후에, A에 eax레지스터의 값을 복사, 그리고 B에 0을 복사하여 연산을 마무리한다.
C코드와 정확히 매칭되도록 동작한다고 할 수 있다.
하지만 최적화된 경우 어떨까?

이와 같이 eax 레지스터에 B 값을 복사하고 B에 먼저 0을 복사하고, eax에 1을 더한 다음, 이를 A에 복사하는 식으로 동작한다. 즉, A와 B의 할당 순서가 서로 뒤바뀌게 된다. (연산으로 인한 A, B의 값은 같다. 순서만 다를 뿐이다.)
번외
명령어 수도 같고 종류도 같은데 굳이 왜 순서를 바꿨을까하는 생각에, 블로그 글에는 없지만 왜 이렇게 최적화가 진행되는지 알아봤다.
결론 부터 보자면, 최적화 이전과 이후의 파이프라인이 동작 방식이 다르기 때문이다.
위와 같이 add 명령이 먼저 들어갈 경우 이전 값을 필요로 하게 되므로 write back단계를 기다려야한다. 즉, 이를 기다리면서 한 사이클을 더 소모하게 된다. 하지만 최적화 된 경우에는 stall 없이 파이프라인이 수행되어, 사이클 하나를 아낄 수 있게 된다.
(물론 현대의 x86-64 아키텍쳐의 경우에는 보다 복잡한 파이프라인을 가지므로 해당 설명이 현실에서 적합하지 않을 수 있다. 이론적 참고로만 확인하도록 하자)
다시 이야기로 돌아가서 그럼 최적화 경우와 같이 할당 순서가 바뀔 경우 어떤 문제가 발생할 수 있을까?

위와 같이 value로 값을 설정하고 IsPublished로 값이 설정됨을 확인한다고하면 문제가 발생한다.
다른 스레드에서 동작한다고 가정 할 때, IsPublished를 읽은 시점에 Value가 설정되지 않을 수도 있음을 의미하기 때문이다.
이를 막는 방법은 무엇인가?
두 가지 경우로 이를 나눌 수 있는데, 먼저 컴파일러 최적화 단계에서 reordering이 일어나지 않도록 하는 것이고, 두 번째는 CPU단계에서 이를 보장하는 방법이다.
만약 싱글코어일 경우에는 대부분의 경우 해당 방법으로 충분할 것이다.

하지만 현대 시스템에서는 임베디드 프로세서가 아닌 이상에야, 멀티 코어를 기본적으로 가지므로, 다음과 같은 CPU 단계에서의 보장이 필요하다.
임베디드 프로세서를 다루는 중, 궁금한 것을 찾아본 것이기에 여기서 마무리하고자 한다. PC에서 같은 상황을 맞이할 경우 이어서 작성하도록 한다.
(CPU에서 메모리 동기화를 보장하기 위한 방법)
참고자료
https://preshing.com/20120625/memory-ordering-at-compile-time/ cpumemory.pdf hwViewForSwHackers.pdf
