
앞선 포스팅에서 데드락 현상에 대해 가볍게 살펴봤다.
데드락(Deadlock)은 컴퓨터 과학에서 여러 프로세스나 스레드가 서로를 무한히 기다리는 상태를 말한다. 이 상태에서는 모든 관련 프로세스나 스레드가 정지 상태에 빠져, 작업을 계속할 수 없게 된다.
데드락은 일반적으로 다음과 같은 네 가지 조건이 동시에 만족될 때 발생합니다:
- 상호 배제(Mutual Exclusion): 자원은 한 번에 하나의 프로세스만이 사용할 수 있다. 다른 프로세스는 그 자원이 해제될 때까지 기다려야 한다.
- 보유 및 대기(Hold and Wait): 프로세스가 최소한 하나의 자원을 보유하고 있으면서 동시에 다른 프로세스가 사용 중인 추가 자원을 기다리고 있다.
- 비선점(No Preemption): 프로세스가 자원을 스스로 해제하기 전까지 다른 프로세스가 그 자원을 뺏을 수 없다.
- 순환 대기(Circular Wait): 두 개 이상의 프로세스가 서로의 자원을 기다리는 순환 형태의 체인이 형성된다. 예를 들어, 프로세스 A는 B가 보유한 자원을 기다리고, 프로세스 B는 C가 보유한 자원을 기다리고, C는 다시 A가 보유한 자원을 기다리는 식.
데드락이 발생하면, 관련된 프로세스들은 더 이상 진행할 수 없게 되며, 이로 인해 시스템의 일부 또는 전체가 멈추게 된다.
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)
{
}
}
}
internal 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(number);
}
}
}
Thread_1은 SessionManager.Test()를 호출한다. 이 메소드는 SessionManager의 락을 획득하고, 그 안에서 UserManager.TestUser()를 호출한다. UserManager.TestUser()는 UserManager의 락을 획득하려고 한다.
Thread_2는 UserManager.Test()를 호출한다. 이 메소드는 UserManager의 락을 획득하고, 그 안에서 SessionManager.TestSession()을 호출한다. SessionManager.TestSession()는 SessionManager의 락을 획득하려고 한다.
이 시점에서 데드락이 발생할 수 있다. 만약 Thread_1이 SessionManager의 락을 획득하고 UserManager의 락을 기다리는 동안, Thread_2가 UserManager의 락을 획득하고 SessionManager의 락을 기다린다면, 두 스레드는 서로가 가진 락을 기다리며 무한정 대기하게 된다
데드락은 미리 예방하기보다는 크러쉬가 나면 그 후에 데드락이 발생한 위치를 찾고 문제를 해결하는 것이 더욱 간단할 수 있다.
1) Thread간 시간차를 준다. (락을 획득하는 순서를 일관되게 유지)
