요약

교착상태 예방은 네 조건 가운데 하나가 아예 생기지 못하도록 시스템을 처음부터 설계하는 것이다. 네거리에 “모든 차는 시계 방향 순서로만 칸을 잡는다”는 규칙을 두면 원이 생길 수 없는 것과 같다. 일단 설계해 두면 실행 중에 따질 것이 없다. 대신 자원을 필요 이상으로 오래 잡거나, 쓸 수 있는 자원을 놀리게 만들어 효율이 떨어진다.

예시로 보기

스레드 둘이 계좌 두 개의 잠금을 잡고 이체한다1.

  • 스레드 1: 계좌 A 잠금 → 계좌 B 잠금 (A → B 이체)
  • 스레드 2: 계좌 B 잠금 → 계좌 A 잠금 (B → A 이체)

둘이 동시에 첫 잠금을 잡으면 순환 대기가 생긴다. “계좌 번호가 작은 쪽부터 잠근다”는 규칙 하나로 둘 다 A → B 순서가 되어 원이 생기지 않는다. 이것이 순환 대기를 깨는 예방이다.

정확히 말하면

교착상태가 생길 가능성 자체를 없애도록 시스템을 설계한다. 방법은 둘이다.

  • 간접 예방: 앞의 세 조건(상호 배제, 점유와 대기, 비선점) 중 하나를 막는다.
  • 직접 예방: 순환 대기를 막는다.
깨는 조건 방법 대가
상호 배제 막을 수 없다. 프린터나 파일 쓰기처럼 한 번에 하나만 써야 하는 자원이 있으면 운영체제가 상호 배제를 지원해야 한다 —
점유와 대기 프로세스가 필요한 자원을 한 번에 모두 요청하게 한다. 다 받을 때까지 기다린다 모든 자원이 모일 때까지 오래 기다릴 수 있다. 받은 자원을 오래 쓰지 않은 채 쥐고 있다. 필요한 자원을 미리 다 알아야 한다1
비선점 자원을 쥔 프로세스가 다른 요청을 거절당하면 쥔 것을 놓고 나중에 다시 요청하게 한다. 또는 운영체제가 다른 프로세스에게 자원을 놓으라고 선점할 수 있다 상태를 저장했다 되돌리기 쉬운 자원(프로세서 등)에만 맞다. 필요 이상으로 자주 선점한다
순환 대기 자원 종류에 선형 순서를 정한다. 자원 \(R_i\)를 쥔 프로세스는 \(i\)보다 뒤 순서의 자원만 요청할 수 있다 자원을 순서대로만 받으므로, 지금 필요 없는 자원도 미리 받아야 할 수 있다

순환 대기 예방이 통하는 이유. 프로세스 A가 \(R_i\)를 쥐고 \(R_j\)를, B가 \(R_j\)를 쥐고 \(R_i\)를 기다린다고 하자. 규칙에 따르면 A의 요청은 \(i < j\), B의 요청은 \(j < i\)를 뜻한다. 둘은 동시에 맞을 수 없다. 원이 몇 단계로 길어져도, 원을 따라가면 순서가 계속 커지다가 출발점으로 돌아와야 하므로 모순이다1.

세 방법의 장단점 (표 6.1의 예방 부분)

방식 좋은 점 나쁜 점
한 번에 모두 요청 한 번 몰아서 일하고 끝나는 프로세스에 잘 맞는다. 선점이 필요 없다 비효율적이다. 프로세스 시작이 늦어진다. 앞으로 필요한 자원을 미리 알아야 한다
선점 상태를 저장·복원하기 쉬운 자원에 편하다 필요 이상으로 자주 선점한다
자원 순서 컴파일할 때 검사할 수 있다. 설계에서 풀리므로 실행 중 계산이 없다 자원을 조금씩 늘려 요청할 수 없다

예방 전체는 보수적이다. 자원을 필요보다 덜 내준다.

활용

  • 리눅스 커널은 잠금마다 잡는 순서를 정해 두고, 검사 도구(lockdep)로 순서를 어기는 코드를 찾는다1.
  • 식사하는 철학자 문제의 해법 하나도 포크에 번호를 매겨 작은 번호부터 잡게 하는 것이다 → 식사하는 철학자 문제

연결

확인 문제

C1 다음 각 규칙은 네 조건 중 무엇을 깨는가? ① 프로그램 시작 때 쓸 파일을 모두 연다 ② 잠금은 주소가 작은 것부터 잡는다 ③ 두 번째 잠금을 못 얻으면 첫 잠금을 놓고 처음부터 다시 한다

답: ① 점유와 대기 ② 순환 대기 ③ 비선점(스스로 놓음).

C2 상호 배제 조건을 깨서 교착상태를 예방하는 방법은 왜 일반적으로 쓸 수 없는가?

답: 프린터 출력이나 파일 쓰기처럼 본질적으로 한 번에 하나만 써야 하는 자원이 있다. 이런 자원을 여럿이 동시에 쓰게 하면 경쟁 조건이 생긴다. 상호 배제는 막을 대상이 아니라 지켜야 할 성질이다.

C3 자원에 순서를 정하고 오름차순으로만 요청하게 하면 왜 순환 대기가 생길 수 없는가? 프로세스 셋 P1→P2→P3→P1의 원을 가정하고 모순을 보여라.

답: P1이 쥔 자원 번호를 \(a\), P2가 쥔 것을 \(b\), P3가 쥔 것을 \(c\)라 하자. P1은 쥔 \(a\)보다 큰 \(b\)를 기다리므로 \(a < b\). 마찬가지로 \(b < c\), \(c < a\). 합치면 \(a < b < c < a\)로 모순이다.

  1. 계좌 이체 예, 각 방법의 대가 설명, 순환 대기 예방의 증명, 리눅스 lockdep, 확인 문제는 Stallings 6판 6.2절을 바탕으로 보탰다. ↩ ↩2 ↩3 ↩4