ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스핀락(SpinLock)
    게임서버/멀티쓰레드 프로그래밍 2022. 3. 11. 13:03

    1. 스핀락 구현

        class SpinLock
        {
            volatile bool _locked = false; // 락이 열리면 false, 잠기면 true
            public void Acquire() // Monitor.Enter() 역할
            {
                while (_locked)
                {
                    // 잠김이 풀리기를 기다린다.
                }
    
                // 자물쇠는 내꺼!
                _locked = true;
            }
            public void Release() // Monitor.Exit() 역할
            {
                _locked = false;
            }
        }

    주석을 통해 스핀락의 특징들을 구현해봤으며 그렇게 복잡하지는 않다.

     

        class Program
        {
            static int num = 0;
            static SpinLock _lock = new SpinLock();
    
            static void Thread_1()
            {
                for(int i= 0; i<100000; i++)
                {
                    _lock.Acquire();
                    num++;
                    _lock.Release();
                }
            }
    
            static void Thread_2()
            {
                for (int i = 0; i < 100000; i++)
                {
                    _lock.Acquire();
                    num--;
                    _lock.Release();
                }
            }
            static void Main(string[] args)
            {
                Task t1 = new Task(Thread_1);
                Task t2 = new Task(Thread_2);
                t1.Start();
                t2.Start();
    
                Task.WaitAll(t1, t2);
    
                Console.WriteLine(num);
            }
        }
    }

    그리고 구현한 스핀락을 실제로 써보고 실행하면 이상한 값이 나옴을 알 수 있다.

     

    그 이유를 분석해보면 락을 동시에 점유해버리는 문제가 발생했기 때문이다.

    동시에 점유하는 문제(num++관련)는 예전에도 나왔었는데 이것 또한 그때처럼 Interlocked 계열의 함수로 해결할 수 있다.

     

        class SpinLock
        {
            volatile int _locked = 0; // 락이 열리면 0, 잠기면 1
            public void Acquire()
            {
                while (true)
                {
                    int original = Interlocked.Exchange(ref _locked, 1);
                    if (original == 0)
                        break;
                }
    
            }
            public void Release()
            {
                _locked = 0;
            }
        }

    Interlocked.Exchange가 인자로 정수형을 받기 때문에 _locked변수의 자료형도 정수형으로 바꿨다.

     

    Compare-And-Swap

        class SpinLock
        {
            volatile int _locked = 0; // 락이 열리면 0, 잠기면 1
            public void Acquire()
            {
                while (true)
                {
                    // CAS(Compare-And-Swap)
                    int comparand = 0;
                    int value = 1;
                    if (Interlocked.CompareExchange(ref _locked, value, comparand) == comparand)
                        break;
                }
    
            }
            public void Release()
            {
                _locked = 0;
            }
        }

    Interlockec.CompareExchange는

    _locked와 comparand값을 비교하여 둘의 값이 일치하면 value값을 _locked값에 넣어주는 함수이다.

    '게임서버 > 멀티쓰레드 프로그래밍' 카테고리의 다른 글

    오토리셋이벤트(AutoResetEvent)  (0) 2022.03.11
    컨텍스트 스위칭(Context Switching)  (0) 2022.03.11
    Lock 구현 이론  (0) 2022.03.11
    데드락  (0) 2022.03.10
    Lock 기초  (0) 2022.03.10
Designed by Tistory.