-
데드락게임서버/멀티쓰레드 프로그래밍 2022. 3. 10. 21:30
1. 자물쇠가 2개인 경우
1번쓰레드가 1번자물쇠를 가지고있고
2번쓰레드가 2번자물쇠를 가지고있다고 가정했을 때
1번쓰레드가 1번자물쇠를 가진상태에서 2번자물쇠에 접근하려고 대기하고,
2번쓰레드가 2번자물쇠를 가진상태에서 1번자물쇠에 접근하려고 대기하면 교착상태가 발생한다.
데드락발생 위의 데드락을 방지하기 위해서는 쓰레드끼리 1번자물쇠부터 먼저 접근하고 그 다음에 2번자물쇠에 접근하게끔 설정해주면된다. 그러면 먼저 도착한 쓰레드가 1번자물쇠를 사용하고 락을 해제하면 다음에 도착한 쓰레드가 1번을 사용하게 되기 때문에 교착상태가 발생하지 않는다.
코드로 살펴보면 아래와 같다.
using System; using System.Threading; using System.Threading.Tasks; namespace ServerCore { class SessionManager { static object _lock = new object(); public static void TestSession() { lock (_lock) { } } public static void Test() { lock (_lock) { UserManager.TestUser(); } } } class UserManager { static object _lock = new object(); public static void Test() { lock (_lock) { SessionManager.TestSession(); } } public static void TestUser() { lock (_lock) { } } } class Program { static int number = 0; static object _obj = new object(); static void Thread_1() { for (int i = 0; i < 10000; i++) { SessionManager.Test(); } } static void Thread_2() { for (int i = 0; i < 10000; i++) { UserManager.Test(); } } 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("빠져나옴!"); } } }
실제로 코드를 실행해보면 교착상태에 빠지는 것을 알 수 있다.
2. 해결방법
방법1. Monitor.TryEnter
Monitor.TryEnter(_lock, 100);
0.1초동안 락을 획득하지 못하면 다시 돌아오는 방법이다.
그런데 애초에 교착상태가 발생했다는 것은 구조적으로 문제가 있는 것이기 때문에 그냥 새롭게 고치는 방법을 권유한다.
방법2. Thread.Sleep()
static void Main(string[] args) { Task t1 = new Task(Thread_1); Task t2 = new Task(Thread_2); t1.Start(); Thread.Sleep(100); // 0.1초 후 실행 t2.Start(); Task.WaitAll(t1, t2); Console.WriteLine("빠져나옴!"); }
동시에 락을 서로 획득하려고 하면 교착상태가 발생하기 때문에 0.1초의 시간차를 줘서 데드락을 막는 방법이다.
사실 미리 방지하는 방법은 별로 없고 그냥 크래시가 날때마다 데드락을 확인하는 방법이 유일하다.
'게임서버 > 멀티쓰레드 프로그래밍' 카테고리의 다른 글
스핀락(SpinLock) (0) 2022.03.11 Lock 구현 이론 (0) 2022.03.11 Lock 기초 (0) 2022.03.10 Interlocked (0) 2022.03.10 메모리 베리어 (0) 2022.03.10