[C++] Visual C++의 volatile
지난번 글 에서 말했듯이 C++ 11 이전에는 메모리 접근의 순서를 보장할 수 있는 표준 방법이 없었다. 따라서 플랫폼에 따라 다른 코드를 사용해야 했다. x86은 mfence , ARM이라면 DMB 인스트럭션을 인라인 어셈블리 를 사용하여 집어넣거나, gcc의 __sync_synchronize 나 Visual C++의 MemoryBarrier 매크로를 사용하는 방법이 일반적이다. 여기에 Visual C++은 volatile 에 추가적인 제약을 거는 방법으로 메모리 접근 순서를 보장하는 방법을 마련하였다. Visual C++의 컴파일 옵션에서는 volatile 의 동작을 2가지 중 하나로 선택할 수 있다. /volatile:iso 로 컴파일하면, iso 표준대로 메모리 접근 순서와 상관없이 as-if rule 에 의해 코드가 최적화되어 사라지는 것만을 방지한다. 하지만 /volatile:ms 로 컴파일하면 iso 표준에서 규정하는 제약에 추가적으로 volatile object에 접근하는 것이 load-acquire, store-release semantic 을 따른다. 즉, 간략히 말하면 store는 뒤에 있는 load가 실행된 다음에 실행될 수 있지만, 다른 메모리 접근의 순서는 순서대로 실행되는 게 보장된다. 컴파일 때 아무 옵션을 안 주면 x86에서는 /volatile:ms 가 기본값이다. 사실 x86 CPU는 load-acquire, store-release semantic을 따르기 때문에 volatile object에 접근하는 코드는 컴파일 타임에 순서를 바꾸지 않겠다는 것이다. ARM에서는 /volatile:iso 가 기본값이다. 따라서 /volatile:ms 를 이용하여 컴파일하면 DMB 인스트럭션을 이용하여 CPU가 순서를 바꿔 실행하는 것을 막기 때문에 성능이 떨어진다. 하지만 x86에서 테스트 된 코드를 그대로 사용할 수 있다.