게임 서버 프로그래밍

데드락(Deadlock) 이해하기

유니얼 2024. 3. 18. 17:48
728x90

C# 게임 서버 만들기

멀티쓰레딩 환경에서는 다양한 이점을 제공함과 동시에 여러 도전 과제를 안고 있습니다. 그중에서도 데드락(Deadlock)은 가장 주의해야 할 문제 중 하나입니다. 이 글에서는 데드락이 무엇인지, 왜 발생하는지, 그리고 어떻게 예방할 수 있는지에 대해 알아보겠습니다.

데드락(Deadlock)이란?

데드락은 멀티쓰레딩 환경에서 두 개 이상의 쓰레드가 서로 다른 쓰레드가 보유한 자원의 해제를 무한히 기다리는 상황을 말합니다. 이로 인해 모든 쓰레드가 영원히 대기 상태에 빠지며, 프로그램은 더 이상 진행되지 않는 상태에 이릅니다.

데드락 발생 조건

데드락이 발생하기 위해서는 다음 네 가지 조건이 모두 충족되어야 합니다:

  1. 상호 배제(Mutual Exclusion): 자원은 한 번에 하나의 쓰레드만이 사용할 수 있어야 합니다.
  2. 점유 대기(Hold and Wait): 적어도 하나의 쓰레드가 자원을 점유한 채 다른 쓰레드가 점유한 자원을 추가로 요구하며 대기해야 합니다.
  3. 비선점(No Preemption): 자원은 그 자원을 보유하고 있는 쓰레드가 스스로 해제할 때까지 다른 쓰레드에 의해 강제로 빼앗길 수 없습니다.
  4. 순환 대기(Circular Wait): 대기하는 쓰레드들 사이에 순환 형태의 체인이 존재해야 합니다. 이 체인에서 각 쓰레드는 다음 쓰레드가 요구하는 자원을 보유하고 있습니다.

데드락 예방 및 해결

데드락을 예방하고 해결하는 전략은 다음과 같습니다:

  • 상호 배제 제거: 가능한 경우 자원을 공유할 수 있도록 하여 상호 배제 조건을 제거합니다. 그러나 이 방법은 모든 상황에 적용할 수 없습니다.
  • 점유 대기 조건 제거: 한 번에 모든 필요한 자원을 요청하도록 알고리즘을 설계하여, 이미 점유한 자원을 보유한 상태에서 추가 자원을 대기하지 않도록 합니다.
  • 비선점 조건 제거: 필요한 자원이 사용 중일 때는 보유 중인 모든 자원을 해제하고, 나중에 다시 모든 자원을 요청하도록 합니다.
  • 순환 대기 조건 제거: 모든 자원에 일정한 순서를 부여하고, 순서에 따라 자원을 요청하도록 함으로써 순환 대기를 방지합니다.

예제 코드

using System;
using System.Threading;

class DeadlockExample
{
    private static readonly object lock1 = new object();
    private static readonly object lock2 = new object();

    static void Thread1Method()
    {
        lock (lock1)
        {
            Console.WriteLine("Thread 1 acquired lock1");
            Thread.Sleep(100); // 다른 쓰레드가 lock2를 획득할 시간을 제공
            lock (lock2)
            {
                Console.WriteLine("Thread 1 acquired lock2");
            }
        }
    }

    static void Thread2Method()
    {
        lock (lock2)
        {
            Console.WriteLine("Thread 2 acquired lock2");
            Thread.Sleep(100); // 다른 쓰레드가 lock1을 획득할 시간을 제공
            lock (lock1)
            {
                Console.WriteLine("Thread 2 acquired lock1");
            }
        }
    }

    static void Main(string[] args)
    {
        Thread t1 = new Thread(new ThreadStart(Thread1Method));
        Thread t2 = new Thread(new ThreadStart(Thread2Method));

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();
    }
}

결론

데드락은 멀티쓰레딩 프로그램에서 발생할 수 있는 복잡한 문제입니다. 데드락을 효과적으로 관리하고 예방하기 위해서는 프로그램 설계 단계에서부터 주의 깊게 고려해야 합니다. 위에서 언급한 데드락의 조건을 이해하고, 예방 전략을 적용함으로써 멀티쓰레딩 애플리케이션의 안정성과 신뢰성을 크게 향상시킬 수 있습니다.

반응형