-
스핀락(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