배경
이전에 TADAK 프로젝트를 진행하면서 서버에서 순환 참조 문제가 발생했던 적이 있다. 이때 발생한 순환 참조란 A 모듈이 → B 모듈을 필요로 하고, B 모듈이 → A 모듈을 필요로 해서 undefined 오류 또는 로딩 실패가 발생하는 것이다.
이처럼 순환 참조 문제는 모듈/객체에서 발생한 것으로 모듈을 정의하고 참조할 때 발생하는 것이다. 이를 해결하기 위해 forwardRef(), 구조 분리를 적용했었다.
운영체제와 관련해서 공부를 하다보니 '교착상태(DeadLock)'이라는 유사한 개념이 있어서 정리해보려고 한다.
DeadLock은 더 넓은 개념으로 실행 중인 자원 경쟁에서 발생하는 문제라고 보면 된다. A 프로세스가 → B의 자원을 대기하고, B 프로세스가 → A의 자원을 대기할 때 발생하는 것이다. 이를 교착상태라고도 한다.

교착상태 (DeadLock)
이처럼 교착 상태란 시스템 자원에 대한 프로세스가 뒤엉킨 상태로, 둘 이상의 프로세스가 다른 프로세스가 점유하고 있는 자원을 서로 기다릴 때 무한 대기에 빠지는 상황을 말한다.
이를 해결하기 위해서는 교착 상태가 발생했을 때의 상황을 그래프로 표현해보고, 근본적인 이유를 이해해야 한다.
아래의 4가지 조건 중 하나라도 만족하지 않으면 교착 상태가 발생하지 않는다. 즉, 4가지 조건을 모두 만족해야 교착 상태가 발생한다.
교착상태 발생 4가지 조건
1. 상호 배제 (Mutual Exclusion)
- 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없는 상태
2. 점유와 대기 (Hold and Wait)
- 자원을 할당 받은 상태에서 다른 자원을 할당 받기를 기다리는 상태
3. 비선점 (No preemption)
- 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못하는 상태
4. 원형 대기 (Circular wait)
- 프로세스들이 원의 형태로 자원을 대기하는 상태
교착상태 해결 방법
1. 예방
애초에 교착 상태가 발생하지 않도록 하는 것이다. 교착 상태 발생 조건 중 하나를 없애버리는 방식으로 예방할 수 있다.
- 1-1) 상호 배제를 없애면? → 모든 자원을 공유할 수 있게 만드는 것은 현실적으로 불가능
- 1-2) 점유와 대기를 없애면? → 특정 프로세스에 자원을 모두 할당하거나, 아예 할당하지 않는 방식으로 배분 → 자원의 활용률을 낮출 수 있는 방식
- 1-3) 비선점 조건을 없애면? → 선점이 가능한 자원(eg. CPU)에 대해서는 효과적 → 하지만 모든 자원이 선점 가능한 것은 아님
- 1-4) 원형 대기 조건을 없애면? → 자원에 번호를 붙이고 오름차순으로 할당하면 원형 대기는 발생하지 않음 → 가장 현실적이지만 번호를 붙이는 것은 어려운 작업이고 활용률이 달라질 수 있음
예방하는 방법은 명확하지만 여러 가지 부작용이 따르는 방식일 수 있다.
2. 회피
교착 상태를 무분별한 자원 할당으로 인해 발생했다고 간주한다. 따라서 교착 상태가 발생하지 않을만큼 배분할 수 있는 양을 고려하여 자원을 할당한다.
- 2-1) 안전 순서열: 교착 상태 없이 안전하게 프로세스들에 자원을 할당할 수 있는 순서
- 2-2) 안전 상태: 교착 상태 없이 모든 프로세스가 자원을 할당 받고 종료될 수 있는 상태 → 안전 순서열이 있는 상태
- 2-3) 불안전 상태: 교착 상태가 발생할 수도 있는 상태 → 안전 순서열이 없는 상태
즉, 안전 상태에서 안전 상태로 움직이는 경우에만 자원을 할당하는 방식이라고 할 수 있다. 예방법보다는 조금 덜 제한적인 방법으로 예방법의 단점을 일부 해결할 수 있다.
이와 관련해서 교착상태 회피를 하는 대표적인 은행원 알고리즘이 있다.
- 은행원 알고리즘은 프로세스의 모든 요구를 유한한 시간 안에 할당하는 것을 보장한다.
- 특정 프로세스가 자원을 요청했을 때 해당 요청으로 시스템이 불안전 상태에 빠진다면 이를 거절하는 방식이다.
- 계속해서 안전상태를 유지해야하기 때문에 자원 사용률이 낮다.
- 프로세스는 최대 자원 요구량을 미리 파악해야 하며 자원을 반드시 순환시켜야 하는 부담이 있다.
3. 검출 후 회복
교착 상태의 발생을 인정하고 사후에 조치하는 방식이다. 프로세스가 자원을 요구하면 일단 할당하고, 교착 상태가 검출되면 회복하는 것이다.
- 3-1) 선점을 통한 회복: 교착 상태가 해결될 때까지 한 프로세스씩 자원을 몰아주는 방식
- 3-2) 프로세스 강제 종료를 통한 회복: 교착 상태에 놓인 프로세스를 모두 강제 종료(→ 작업내역을 잃을 위험) / 하나씩 강제 종료(→ 오버헤드)