본문 바로가기
cs공부/운영체제

운영체제 - DeadLock(데드락)

by 코딩하는 돼징 2023. 5. 22.
반응형

데드락

자물쇠를 2개다 획득해야만 화장실에 들어갈 수 있다고 가정.해보자.

두 사람이 있다면 각각 사람이 1개씩 자물쇠를 가지고 그 다음 자물쇠를 가질려고 할 때 이미 한 개씩은 가지고 있으므로 모두 자물쇠를 하나씩 더 획득하는 것이 불가능하게 된다.

이와 같은 상황이 발생하는 이유는 자물쇠를 잠그는 순서가 안맞기 때문이다.

A사람은 1번자물쇠를 먼저 잠그고 B사람은 2번 자물쇠를 먼저 잠그기 때문에 서로 사이클이 일어나는 문제가 발생한다.

 

 

왜 화장실은 한개인데 자물쇠를 2개 사용하는 상황이 일어날까?

코드상으로 확인

class SessionManager
{
    static object _lock = new object();
    public static void TestSession()
    {
        lock (_lock)
        {

        }
    }
    static void Test()
    {
        lock(_lock)
        {
            UserManager.TestUser();
        }
    }
}
class UserManager
{
    static object _lock = new object();
    public static void TestUser()
    {
        lock(_lock)
        {

        }
    }
    static void Test()
    {
        lock(_lock)
        {
            SessionManager.TestSession();
        }
    }
}

각각의 Thread에서 하나는 SessionManager의 Test를 호출하고 또 다른 하나는 UserManager를 호출하다 보면 꼬이는 현상이 일어나게 된다.


결과를 확인해보자

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("DeadLock아님!");
}

코드를 실행시키면 

DeadLock이 걸린 것을 확인해 볼 수 있다.

 

실행 과정

1. Thread_1과 Thread_2 실행 준비

2. Thread_1이 SessionManager.Test() 메서드에 진입하려고 SessionManager의 _lock개체에 lock을 요쳥한다.

3. Thread_2이 UserManager.Test()메서드에 진입하려고 UserManager의 _lock 객체에 lock을 요청한다. 하지만 _lock개체는 이미 Thread_1에 의해 잠겨있으므로 대기한다.

4. Thread_1이 SessionManager.Test() 메서드 내부에서 UserManager.TestUser() 메서드를 호출한다. 이때 _lock객체를 요청하려고 하지만 이미 Thread_1에 의해 잠겨있으므로 대기 상태에 들어간다. Thread_1과 Thread_2가 서로 상대의 lock를 기다리면서 대기 상태로 빠지게 되어 데드락이 발생한다.


Monitor.TryEnter를 통해서 문제를 해결할 수 있지 않을까?

Monitor.TryEnter를 통해서 내가 몇초동안 시도를 해보다가 락을 획득하는데 실패하면 깔끔하게 포기하겠다. -> 이를 실제 코드에 사용하게되면 코드 락 구조 자체가 문제가 있기 때문에 이 또한 문제가 된다.


결론

데드락이 일어나게 되면 그 상황에 맞춰서 고치는 것이 제일 좋다. 데드락은 예방하기 힘들지만 이유를 찾아 고치는 것이 더 쉬울 수 있다.

데드락은 막상 개발단계에서 안일어날 수 있는데 라이브 상황에서 유저들이 몰릴때 터지는 경우가 많다.

대부분 Session과 User가 동시에 따단 실행하는 경우가 드물다. User가 접속할 때 user와 관련된 부분이 실행되고 usersession이랑 관련된 부분이 있을때 실행된다. 


예방 방법

01 시작 시간 겹치지 않게 하기

그러므로 띄엄띄엄 일어난다고 가정을 해서 Thread.Sleep을 넣게 된다.

t1.Start();
Thread.Sleep(100);
t2.Start();

DeadLock이 아님을 확인할 수 있다.

정확하게 둘이 일치한 타이밍에 실행을 하는 경우에만 맞물리는 현상이 발생하게 된다. 조금만 시작 시간이 어긋나게 되면 DeadLock이 발생하지 않는 것을 확인할 수 있다.


02 Lock 미리 맵핑하기(fair locking)

각각 id를 하나씩 부여한다. 그리고 실행을 한 후 내가 lock을 잡고 있는 상태에서 다른 애를 실행하고 내가 갖고 있는 애 보다 id가 높으면은 문제가 있는 것이다. 그리고 바로 crash낼 수 있다.

 

 

 

 

 

 

참고 :  본 내용은 MMORPG  PART4 강의를 수강하여 작성하였습니다.

https://www.inflearn.com/course/%EC%9C%A0%EB%8B%88%ED%8B%B0-mmorpg-%EA%B0%9C%EB%B0%9C-part4

 

반응형

댓글