-
Lock 기초게임서버/멀티쓰레드 프로그래밍 2022. 3. 10. 19:42
1. lock
Interlocked를 통해서 원자성을 지키는 것을 저번에 알아보았다.
그러나 Interlocked의 단점은 정수형만 쓸 수 있다는 점이다.
굳이 Interlocked를 쓰지 않아도 원자성을 보장하는 방법이 있는데 그것은 Monitor.Enter와 Monitor.Exit이다
using System; using System.Threading; using System.Threading.Tasks; namespace ServerCore { class Program { static int number = 0; static object _obj = new object(); static void Thread_1() { for (int i = 0; i < 100000; i++) { Monitor.Enter(_obj); // 문을 잠구는 행위 number++; Monitor.Exit(_obj); // 문을 여는 행위 } } static void Thread_2() { for (int i = 0; i < 100000; i++) { Monitor.Enter(_obj); // 문을 잠구는 행위 number--; Monitor.Exit(_obj); // 문을 여는 행위 } } 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(number); } } }
문을 잠구고 혼자 사용하는 행위를 상호배제(Mutual Exclusive)라고 하며 이 안에서는 싱글 쓰레드처럼 프로그래밍을 하여도 된다.
하지만 Monitor안의 코드가 길어져서 아래의 코드와 같이 문을 여는 행위를 실수로 넘겨버릴 수 있다.
for (int i = 0; i < 100000; i++) { Monitor.Enter(_obj); // 문을 잠구는 행위 number++; return; Monitor.Exit(_obj); // 문을 여는 행위 }
return키워드로 인해서 문을 여는 행위가 의도치 않게 스킵되어버렸다.
문을 열지 못해서 더 이상 열쇠를 사용하지 못하는 경우를 죽은열쇠(Deadlock)라고 표현한다.
데드락을 막기위한 방법을 알아보자.
방법1. return위에 문을여는 코드삽입
static void Thread_1() { for (int i = 0; i < 100000; i++) { Monitor.Enter(_obj); // 문을 잠구는 행위 number++; if(number == 10000) { Monitor.Exit(_obj); // 문을 여는 행위 return; } Monitor.Exit(_obj); // 문을 여는 행위 } }
첫번째 방법은 모든 return위에다가 Monitor.Exit()를 넣어주는 방법이다.
하지만 이렇게 하면 코드가 더러워지고 일일이 다 넣어줘야하는 번거로움이 있어서 좋은 방법은 아니다.
방법2. try ~ finally 사용
static void Thread_1() { for (int i = 0; i < 100000; i++) { try { Monitor.Enter(_obj); // 문을 잠구는 행위 number++; } finally { Monitor.Exit(_obj); // 문을 여는 행위 } } }
try~finally를 사용하면 반드시 문을 여는 행위가 한번은 실행된다.
방법3. lock키워드사용
static void Thread_1() { for (int i = 0; i < 100000; i++) { lock (_obj) { number++; } } }
lock 키워드에는 내부적으로 Monitor.Enter(), Monitor.Exit()가 들어있다.
'게임서버 > 멀티쓰레드 프로그래밍' 카테고리의 다른 글
Lock 구현 이론 (0) 2022.03.11 데드락 (0) 2022.03.10 Interlocked (0) 2022.03.10 메모리 베리어 (0) 2022.03.10 캐시 이론 (0) 2022.03.09