지금까지 이미 데드락에 대해 여러번 설명을 하였지만 한 번 더 설명을 한다.
📌데드락: 다른 쓰레드/프로세스가 서로의 점유하고 있는 자원에 대해 무기한 대기하는 현상
lock 기초를 다룰 때, Monitor를 이용하였는데 이때 Exit를 하지 않은 경우 무한정 대기한 현상이 바로 데드락이다.
오늘은 두 개이상의 lock에 대한 데드락을 간단히 살펴보고, 구체적인 구현은 다음 시간에 진행한다.
코드는 각 쓰레드가 UserManager, SessionManager의 Test 메소드를 1만번 실행시키는 간단한 코드이다.
using System;
using System.Collections.Generic;
using System.Text;
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 Lock_1129
{
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(number);
}
}
}
Console.WriteLine(number)에 break point를 찍고 디버깅을 진행해보자. 당연히 무한 루프가 걸릴 것이다.
디버깅을 일시 중지하고, 쓰레드에서 작업자 쓰레드로 넘어가 무슨일이 생겼는지 확인해보자.
알고보니 쓰레드에서 메소드 Test를 실행시, 자기 자신에게 lock을 먼저 건 후, TestSession, TesetUser 메소드를 실행시킨 것을 볼 수 있다.
그러니까 지난 Monitor 시간엔 한 사람이 하나의 자물쇠를 풀지 않고 영영 빠져나가지 않는 점이라면, 현재의 상황은 한 사람이 두 개의 자물쇠를 가져야 하는데 각자 하나씩의 자물쇠를 쥐고 있는 상황이기에, 아무것도 못하는 상황이다.
현재의 소스코드는 두 개의 쓰레드가 동시에 실행되었기에 이와 같은 현상이 발생한다.
즉, Thread.sleep 등을 이용하여 쓰레드가 잠시 여유를 두고 차례대로 실행되면 데드락은 발생되지 않는 것이다.
데드락은 정말 중요하므로 데드락이 발생할 4가지 조건과, 데드락을 해결하는 방법 등은 기술 면접때 단골 지문이라고 나오니, 찾아서 공부해보자.