class SessionManager
    {
        static object _lock_session = new object(); 
        public static void TestSession()
        {
            lock(_lock_session)
            {}
        }
        public static void Test()
        {
            lock (_lock_session)
            {
                UserManager.TestUser(); 
            }
        }
    }
    class UserManager
    {
        static object _lock_user = new object();
        public static void TestUser()
        {
            lock(_lock_user)
            {}
        }
        public static void Test()
        {
            lock(_lock_user)
            {
                SessionManager.TestSession(); 
            }
        }
    }

    class Program
    {
            

        static int number = 0;
        static object _obj = new object(); 

        static void Thread_1()
        {
            for(int i=0; i<100; i++)
            {
                SessionManager.Test(); 
                
            }
        }

        static void Thread_2()
        {
            for(int i=0; i<100; 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("데드락에 걸리지 않았다!");
        }
    }

 

 

Thread_1 에서 SessionManger.Test를 호출할 때 _lock_session을 사용해서 Lock을 걸고

이때 동시에 Thread_2 는 UserManger.Test를 호출해서 _lock_user를 사용해서 Lock을 건다.

 

Thread_1은 SessionManger.Test를 통해 UserManger.TestUser를 호출할 때 _lock_user로 Lock을 걸어야 한다.

근데 Thread_2에서 _lock_user를 사용하고 있다보니까 Lock을 걸 수 없고

 

마찬가지로, Thread_2 역시 UserManger.Test를 통해 SessionManager.TestSession을 호출할 때
_lock_session으로 Lock을 걸어야 하는데

Thread_1에서 이미 사용하고 있다보니 Lock을 걸 수 없다 보니

 

데드락에 빠지게 된다.

 

 

 

 

 

번외로, 데드락이 나면 예외처리로 고치기 보다는 차라리 크래쉬를 내는 것이 더 좋다.

Lock 구조에 문제기 있어 데드락이 발생한거기 때문에 그 상황에서 예외처리를 하는 것은 장기적인 관점에서 좋지 않다. 훗날 어떤 예외가 튀어 나올지 모르기 대문이다.

 

또 데드락이 무서운 이유는 조금의 시간차가 있으면 발생하지 않을 수 있기 때문이다.

위 코드에서

t1.Start();

Thread.Sleep(100); 

t2.Start();

t1과 t2의 시작 시간을 다르게 해주면 코드가 정상적으로 작동하는 것을 볼 수 있다.

 

이것은 임시적인 방인이다

 

 

ref :https://velog.io/@kkuoo7/DeadLock

반응형

+ Recent posts