UnityServer - 메모리 배리어

k_hyun·2022년 10월 26일
0

Unity_Server

목록 보기
4/32

코드 실행

		static int x = 0;
        static int y = 0;
        static int r1 = 0;
        static int r2 = 0;

        static void Thread_1()
        {
            y = 1;

            r1 = x;
        }

        static void Thread_2()
        {
            x = 1;

            r2 = y;
        }

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

                Task t1 = new Task(Thread_1);
                Task t2 = new Task(Thread_2);
                t1.Start();
                t2.Start();

                Task.WaitAll(t1, t2);

                if (r1 == 0 && r2 == 0)
                    break;
            }
            Console.WriteLine($"{count}번 작동");
        }


위의 코드를 실행하면 while문이 103번이 작동함을 알 수 있었다.

이는 쓰레드에서 y와 r1, 그리고 x와 r2가 연관이 없기에 하드웨어에서 최적화를 하기 때문이다.

		static void Thread_1()
        {            
            r1 = x;
            
            y = 1;
        }

        static void Thread_2()
        {
            r2 = y;
            
            x = 1;
        }

즉 위의 방식으로 작동했다는 의미가 된다.

메모리 배리어

Thread.MemoryBarrier();

각 Thread에서 Load와 Store하는 문장 사이에 위의 코드를 작성한다.

기대한 무한루프가 작동되는 것을 확인하였다.

이는 Thread.MemoryBarrier()는 코드 재배치를 억제하는 기능이기 때문이다.

가시성

메모리 배리어는 코드의 재배치 뿐만 아니라 가시성도 챙겨준다.

		int _answer;
        bool _complete;

        void A()
        {
            _answer = 123;
            Thread.MemoryBarrier();
            _complete = true;
            Thread.MemoryBarrier();
        }

        void B()
        {
            Thread.MemoryBarrier();
            if (_complete)
            {
                Thread.MemoryBarrier();
                Console.WriteLine(_answer);
            }
        }

        static void Main(string[] args)
        {

        }

A 에서 _answer의 값을 write 해주고 MemoryBarrier()을 실행하면 해당 값을 메모리에도 갱신하는 효과가 있다.

즉 캐쉬의 값을 바로 가져오지 않고 메모리에 있는 값을 확인하여 로드하게 된다.

0개의 댓글