개인공부) 서버 실습(6) - Memory Barrier

Justin·2022년 5월 28일
0

서버공부

목록 보기
5/45

지난 시간

지난 시간에 Release 시에 최적화를 자동으로 해주어 오류를 만들던 거를 'volatile' 키워드로 예외처리를 해주는 방법을 사용했는데 이번 메모리 배리어의 경우도 유사하다고 볼 수 있다.

코드 실습

실습을 통해 빠르게 배우는게 이해도 잘 되고 좋은 거 같다. 얼마 후 있을 롤 MSI에서 T1이 우승하길 바라며 코드를 작성했다.

namespace ServerCore
{
    class Program
    {
        static int x = 0;
        static int y = 0;
        static int r1 = 0;
        static int r2 = 0;

        static void T1()
        {
            y = 1; // Store 
            r1 = x; // Load 
        }
        static void RNG()
        {
            x = 1; // Store
            r2 = y; // Load 
        }

        static void Main(string[] args)
        {
            int count = 0;
            while (true)
            {
                count++;
                x = y = r1 = r2 = 0;

                Task t1Win = new Task(T1);
                Task t1Win2 = new Task(RNG);

                t1Win.Start();
                t1Win2.Start();

                Task.WaitAll(t1Win, t1Win2);

                if (r1 == 0 && r2 == 0)
                    break;
            }

            Console.WriteLine("몇 번만에 성공임? " + count);

        }
    }
}

먼저 위와 같은 코드가 있다고 하자. 코드의 구조를 봤을 때 x, y에 1이 대입하고 그걸 r1, r2에 대입하는 구조로 되어있는데 이렇게 하면 while loop를 빠져나올 수 있을까?

응..?

어떻게 r1, r2가 0이 되는 경우가 생긴걸까? 정답은 역시 최적화에 있었다

T1 함수에서 y =1 라인과 r1 =x 라인이 서로 상관관계가 없기 때문에 내부적으로 판단했을 때 더 좋은 효율을 만들기 위해 순서를 바꾸는 경우가 생긴다.

그래서 x = 0, y = 0 일 때 r1 = x, r2 = y가 되며 두 변수의 값이 0이 되는 상황이 발생한다.

최적화 해주는건 고맙지만, 이런 식으로 나도 모르게 바꿔버리면 곤란해지는 경우가 생길 수 있다. 하지만 컴퓨터는 이런 내 마음을 모르기에 정확하게 알려주어야 한다.

Memory Barrier의 사용

먼저 메모리 베리어에는 두 가지 특성이 있다.

1. 코드의 재배치 억제

위에서 처럼 코드를 맘대로 재배치하여 원하지 않는 결과 도출을 방지해줄 수 있다.

이렇게 순서를 맘대로 바꾸던 곳에 Thread.MemoryBarrier()라는 바리게이트를 세워 서로 순서가 바뀔 수 없게 제한을 해준다.

메모리 베리어를 사용하면 예상하던대로 while loop에 갇히게 된다.

2. 가시성

멀티 쓰레드에서는 서로간에 캐시에만 저장하고 메모리에 공유하지 않아 정보의 불균형이 발생할 수 있다고 저번 캐시 이론에서 공부했었다.

이떄 메모리 베리어를 사용할 경우 캐시에만 등록 되어있던거를 메모리에 올려주거나(Store), 메모리에 저장 된 최신 상태의 값을 가져오는(Load) 역할을 해준다.

유명한 예제중에 하나이며 이걸 이해하면 오늘 배운걸 이해할 수 있다고 한다. 왜 계속 Thread.MemoryBarrier() 하는걸 까? 하지만 주석을 통해 이해하자면

이렇게 Store와 Load를 계속 최신화 해주어 가시성을 높이는 작업을 하기 위해 지속적으로 사용되고 있다. 이러면 원치 않는 결과가 나오는 것을 방지 할 수 있을 것이다.

  • Memory Barrier는 코드 재배치, Store/Load 가시성 증가 외에도 Store만 막거나 Load만 막는 등으로 세분화 할 수도 있다.

profile
인디 게임을 만들며 공부하고 있습니다.

0개의 댓글