lock_guard를 사용하면, unlock을 누락해서 생기는 데드락을 해결할 수 있다. 하지만 lock_guard를 사용해도 데드락은 일어날수 있다.

보통 서버에서는 포인터를 잘못참조해서 일어나는 크래시 문제가 가장 많다. 그리고 여기서 소개할 데드락도 꽤 많이 일어나는 버그.

DeadLock | [C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex m1;
std::mutex m2;

void threadA()
{
    m1.lock();
    std::cout << "A locked m1\\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "A trying to lock m2\\n";
    m2.lock(); // 여기서 블록되며 데드락 가능
    std::cout << "A locked m2\\n";
    m2.unlock();
    m1.unlock();
}

void threadB()
{
    m2.lock();
    std::cout << "B locked m2\\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "B trying to lock m1\\n";
    m1.lock(); // 여기서 블록되며 데드락 가능
    std::cout << "B locked m1\\n";
    m1.unlock();
    m2.unlock();
}

int main()
{
    std::thread t1(threadA);
    std::thread t2(threadB);

    t1.join(); // 데드락 발생 시 이 지점에서 프로그램이 멈춤
    t2.join();
    return 0;
}

스레드A가 락1 → 락2, 스레드B가 락2 → 락1 순서로 락을 걸면 서로 기다리다 멈추는 상황 설명.

본인은 락 매니저를 만들어서 사이클이 발생하는지 추적해서 잡는 편.

그래프 알고리즘에서 순환 싸이클이 일어나는지 판별하는 코드를 만들 수 있는데 이런 방법을 넣어서 디버그 상태에서 사이클이 일어나는지 판별해서 데드락을 잡는 편이다.

데드락을 피하는 방법

1. 데드락을 회피하고 싶다면 순서를 정해서 락을 걸면 된다.

모든 스레드가 여러 락을 항상 같은 순서로 획득하면, 데드락이 발생하지 않는다.

2. 타임아웃 설정

락을 일정 시간내에 획득하지 못하면 포기하고 에러 처리.