← 기술 지식

기술 지식 / 컴퓨터 과학 / 동시성 / 동기화

교착 상태와 대기 그래프

두 계정 잠금과 실행기 고갈의 대기 고리를 그려 보고, 잠금 순서·타임아웃·재시도가 각각 해결하는 범위를 구분합니다.

동시성 · 원리·구현·운영
기술 지식 트리

이 노트는 멈춘 작업을 곧바로 교착이라고 부르지 않고, 자원 소유와 대기 관계를 실제 그래프로 연결하는 방법에서 시작합니다. 두 작업이 잠금을 반대 순서로 얻는 경우와 부모 작업이 자식 작업을 같은 실행기에서 동기 대기하는 경우를 같은 ‘순환 대기’ 모델로 추적한 뒤, 순서 통일·비동기 양보·타임아웃·재시도가 어느 고리를 끊고 어느 문제를 남기는지 구분합니다.

두 작업의 상호 대기와 교착 상태

계정 10에서 20으로 보내는 이체 A와 반대 방향 이체 B가 동시에 실행됩니다. A는 10을 잠그고 20을 기다리며, B는 20을 잠그고 10을 기다립니다. 어느 쪽도 먼저 얻은 잠금을 놓지 않으니 시간이 지나도 진행할 수 없습니다. 이것이 교착 상태(deadlock)입니다.

잠금을 오래 기다린다는 사실만으로 교착이라고 할 수는 없습니다. 소유자가 계산 중이고 결국 잠금을 놓는다면 긴 경합입니다. 교착을 찾으려면 누가 무엇을 가진 채 누구를 기다리는지 연결해야 합니다.

대기 그래프와 교착 조건

반대 순서로 얻은 두 잠금이체 A: 계정 10 잠금 보유, 계정 20 잠금 대기. 이체 B: 계정 20 잠금 보유, 계정 10 잠금 대기20을 놓아야 진행10을 놓아야 진행이체 A계정 10 잠금 보유계정 20 잠금 대기이체 B계정 20 잠금 보유계정 10 잠금 대기
반대 순서로 얻은 두 잠금 화살표는 다른 작업이 가진 자원을 기다리는 관계입니다. 단일 소유 잠금 두 개에서 A와 B가 서로를 기다려 대기 고리가 생깁니다.
그림을 글로 읽기
  • 이체 A: 계정 10 잠금 보유 · 계정 20 잠금 대기
  • 이체 B: 계정 20 잠금 보유 · 계정 10 잠금 대기
  1. 이체 A → 이체 B: 20을 놓아야 진행
  2. 이체 B → 이체 A: 10을 놓아야 진행
순서 이체 A 이체 B
1 계정 10 잠금 획득
2 계정 20 잠금 획득
3 20을 기다리며 10은 보유
4 계속 대기 10을 기다리며 20은 보유

자원을 독점하고, 가진 채 기다리고, 다른 쪽이 강제로 빼앗지 못하고, 순환 대기가 생긴다는 네 조건을 Coffman 조건이라고 부릅니다. 이름을 외우는 데서 멈추지 말고 지금 고리의 어느 연결을 끊을지 선택해야 합니다. 여러 인스턴스를 가진 자원이나 외부에서 공급되는 자원에서는 단순 사이클만으로 교착을 확정할 수 없다는 전제도 중요합니다.

전역 잠금 순서와 대기 고리 차단

계정 ID가 작은 쪽부터 잠그면 A와 B가 모두 10을 먼저 요청합니다. A가 10을 잡았다면 B는 아직 아무 계정 잠금도 가지지 않은 채 기다립니다. A는 20을 얻어 끝낼 수 있으므로 이전 고리가 생기지 않습니다.

transfer(from, to, amount):
    validate(amount > 0)
    if from.id == to.id:
        return same_account_policy
    first, second = sort_by_stable_account_id(from, to)
    lock(first)
    try:
        lock(second)
        try:
            validate(from.balance >= amount)
            newFrom = checked_subtract(from.balance, amount)
            newTo = checked_add(to.balance, amount)
            # 두 계산이 모두 성공한 뒤 비예외적 갱신만 수행
            from.balance = newFrom
            to.balance = newTo
        finally:
            unlock(second)
    finally:
        unlock(first)

이는 메모리 안의 두 계정 상태를 보호하는 슈도코드이지, 프로세스 장애에도 이체를 보존하는 DB 거래 구현은 아닙니다. 객체 참조는 작업 종료까지 유효하고, 잠금 중 변경 연산이 추가 예외를 만들지 않는다는 전제를 둡니다. 실제 저장 거래는 원장과 커밋을 별도로 설계합니다.

관리자 수정·취소·복구 경로도 같은 순서를 따라야 합니다. 한 함수만 고쳐도 호출자가 이미 더 높은 순서의 잠금을 쥔 채 들어오면 고리가 다시 생깁니다. 재귀 잠금은 같은 스레드의 중복 획득을 다룰 뿐 서로 다른 스레드 사이의 고리를 해결하지 않습니다.

실행기 고갈과 부모·자식 작업의 대기 고리

워커가 두 개인 풀에서 P1·P2가 각각 한 워커를 차지한 채 C1·C2를 같은 풀에 제출하고 동기적으로 기다린다고 하겠습니다. C1·C2는 큐에 있지만 두 워커는 부모가 차지하고 있고, 부모는 자식 완료를 기다리므로 어느 쪽도 다음 상태로 나아가지 못합니다. 대기 고리는 부모 → 자식 완료 → 빈 워커 → 부모 종료로 이어집니다.

이 고리는 뮤텍스를 없애거나 계정별 큐로 바꾸어도 남습니다. 비동기 연속 처리로 부모가 실행 자리를 반납하게 하거나, 자식의 실행 용량을 안전하게 분리한 실행기를 사용해야 합니다. 풀 크기만 늘리면 더 많은 부모를 동시에 수용할 뿐, 같은 구조의 대기를 없애지는 못합니다.

서비스 A의 RPC 처리기가 서비스 B를 기다리는데, B가 A의 같은 포화 실행기에 콜백을 보내는 경우도 같습니다. 스레드 덤프와 요청 ID·실행기 큐·분산 추적을 함께 연결해야 로컬 잠금 목록에 보이지 않는 고리를 찾을 수 있습니다.

타임아웃·정리·재시도의 복구 범위

잠금 획득에 시간 제한을 두어 B가 포기하게 하면 대기를 끊을 수 있습니다. 그러나 이미 잡은 잠금을 해제하고 부분 변경을 되돌리는 책임은 남습니다. RAII나 finally는 정리를 돕지만 함수가 대기에서 영원히 돌아오지 않으면 범위 종료 자체가 일어나지 않습니다.

외부 호출 전에 잠금을 풀면 고리를 줄일 수 있지만, 응답이 돌아왔을 때 앞서 읽은 상태는 달라졌을 수 있습니다. 버전이나 기대 상태를 다시 검사해야 합니다. 외부 결제 성공은 로컬 잠금 해제나 DB 롤백으로 취소되지 않습니다.

현상 실제 진행 먼저 살필 것
교착 서로를 기다려 아무도 못 끝냄 소유·대기 고리
라이브락 양보와 재시도는 계속, 완료는 없음 같은 박자의 충돌 반복
기아 다른 작업은 끝나지만 특정 작업만 못 끝냄 공정성·우선순위·대기 상한
긴 경합 느리지만 소유자가 계속 진행 임계 구역 길이·작업량

try-lock 실패 때 모두 놓고 같은 간격으로 재시도하면 라이브락이 생길 수 있습니다. 지터는 충돌 가능성을 낮추지만 개별 작업의 완료 기한을 보장하지 않습니다. 시도 상한과 전체 기한, 공정한 대기 정책을 함께 둡니다.

첫 잠금 획득 직후의 교착 재현 통제

수정 전에는 두 작업이 각각 첫 잠금을 얻은 뒤 장벽에서 만나 다음 잠금을 요청하게 합니다. 둘의 대기 관계가 유지되는지 관찰합니다. 테스트 프로세스 자체가 영원히 멈추지 않도록 외부 제한 시간과 정리 경로를 둡니다.

잠금 순서를 통일한 뒤에는 같은 장벽을 두 첫 잠금 뒤에 그대로 두면 테스트 장벽이 새로운 교착을 만들 수 있습니다. 이제 B는 첫 잠금부터 기다리는 것이 정상입니다. 스케줄러 훅으로 각 획득 시도를 관찰하고 A 완료 뒤 B가 진행하는지 확인해야 합니다. 성공 건수뿐 아니라 계정 합계 보존, 실패 시 자원 반환, 최대 대기와 재시도 횟수를 확인합니다.

재현 연습에서는 먼저 장벽으로 A가 10을, B가 20을 잡은 뒤 서로의 두 번째 잠금을 요청하게 합니다. 예상 관측은 두 작업의 대기 그래프가 A→B와 B→A를 동시에 갖고 외부 제한 시간 안에 완료 건수가 늘지 않는 것입니다. 잠금 순서를 통일한 뒤에는 두 작업이 첫 잠금을 모두 얻어야 통과하는 장벽을 제거해야 합니다. 그 장벽을 유지하면 테스트 자체가 교착을 만듭니다. 별도의 진입 신호로 순서를 제어하면 B가 첫 잠금에서 기다리는 것이 정상이며, A가 두 잠금을 해제한 뒤 B가 완료되는지와 예외·타임아웃 뒤 두 잠금이 모두 반환되는지를 확인해야 합니다.

후속·관련 개념

이 개념의 확장

함께 읽을 문서

전체 기술 지식
선택 연습 · 관련 질문 3개

질문은 이해를 확인하는 보조 자료입니다. 학습 경로와 문서의 범위는 질문 수와 독립적입니다.