컴파일러에 이어서 하드웨어도 우리를 위해 최적화를 해주고 있는데, 이 때문에 서로 연관성이 없는 코드끼리 속도 향상을 위해 순서를 바꿀 수 있다.
순서를 강제할 수 있는 방법은 메모리 배리어를 사용하는 것이다.
위 코드으 경우 Thread.MemoryBarrier를 사용하지 않으면 "count번만에 빠져나옴"이 출력되는 것을 볼 수 있다.
즉 r1과 r2가 0이 되는 경우가 생긴다는 말인데, 이는 Thread1과 Thread2에서 두 줄짜리 코드의 순서가 뒤바뀌면 일어나는 현상이다.
volatile, atomic, lock 같은 개념들도 내부적으로 Memory Barrier가 구현이 되어있다.
추가로 메모리 배리어는 하드웨어 개념임을 기억해야 한다. 메모리 배리어의 사용은 하드웨어 구조를 자세히 공부한 것이 전제가 되어야 하고, 애플리케이션 코드보다는 디바이스 드라이버에서 많이 사용된다.
직원 한명이 테이블에서 주문을 받으면 다른 직원들이 그 주문 받는 내용을 알아야 한다.
그래서 한 직원이 주문을 받으면 수첩에 적고 그 수첩의 내용을 주문 현황판에 적은 다음, 다른 직원들이 주문현황판에서 주문 내용을 가져와서 자신들의 수첩에 적으면 동기화 문제가 발생하지 않을 것이다.
수첩의 내용을 현황판에 적거나 현황판에서 내용을 가져와서 최신화 시키는 작업을 Thread.MemoryBarrier()를 호출하여 실행하고 있다.
위 코드에서 A()와 B가 각각 별도의 쓰레드로 동작하고 있다.
A()에서 _answer에 123을 저장(주문을 받음)하고 곧바로 MemoryBarrier를 통해서 현황판에 갱신시키고 있다. _complete도 마찬가지로 true를 저장하고 바로 갱신시키고 있다.
B()에서도 먼저 MemoryBarrier를 통해 현황판에서 자신의 캐시메모리에 데이터를 가져온 후 _complete를 쓰고 있고, 확실하게 하기 위해 WriteLine하기 전 한번더 MemoryBarrier를 호출하여 _answer를 출력하고 있다.