UnityServer - SpinLock

k_hyun·2022년 10월 27일
0

Unity_Server

목록 보기
8/32

코드

class SpinLock
    {
        volatile bool _locked = false;

        public void Acquire()
        {
            while (_locked)
            {

            }
            _locked = true;
        }

        public void Release()
        {
            _locked = false;
        }
    }

스핀락을 클래스로 구현하여 보았다.

_locked 라는 불리언 변수를 두고 해당 값에 따라 while문을 돌면서 대기하도록 만들었다.

		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);
        }

Thread1과 Thread2는 SpinLock을 활용하여 num값을 증가, 감소시키는 함수이다.

기댓값은 0이다.


결과는 위와 같다.

왜냐하면 Thread1과 Thread2가 거의 동시에 실행되어 Acquire의 while문을 둘 다 통과하는 경우가 생기기 때문이다.

해결

		public void Acquire()
        {
            while (true)
            {
                int original = Interlocked.Exchange(ref _locked, 1);
                if (original == 0)
                    break;
            }
            _locked = 1;
        }

Interlocked.Exchange()를 사용한다.

기존에 _locked의 값은 original로 들어가고, _locked의 값을 1로 갱신한다.

즉 _locked == 0인 경우 락을 획득하게 된다.

		public void Acquire()
        {
            // CAS Compare-And-Swap
            while (true)
            {
                int expected = 0;
                int desired = 1;
                if (Interlocked.CompareExchange(ref _locked, desired, expected) == expected)
                    break;
            }
            _locked = 1;
        }

위와 같이 해결 할 수도 있다.

CompareExchange 함수를 통해, _locked의 값이 expected의 값과 같으면 해당 값을 desired 값으로 바꾼다.

그리고 반환되는 값은 기존의 _locked의 값이 되겠다.

0개의 댓글