낮은 우선순위 스레드가 락을 쥐고 있어 높은 우선순위 스레드가 기다리는 현상.
-
H(높음) — 락을 원한다 → L 이 쥐고 있어 대기
-
M(중간) — 락과 무관한 일을 한다 → L 을 선점해 계속 돈다
-
L(낮음) — 락을 쥔 채 CPU 를 못 받아 일을 못 끝낸다
-
결과: H 가 M 보다 낮은 우선순위처럼 밀린다 (역전)
화성 탐사선 사고
1997 Mars Pathfinder 가 이 문제로 반복 리셋됐다
- 낮은 우선순위 태스크가 뮤텍스를 쥔 채 중간 태스크에 선점당했고,
- 높은 우선순위 태스크가 기한을 넘겨 워치독이 리셋을 걸었다
원격으로 우선순위 상속을 켜 해결했다
해결책
우선순위 상속(priority inheritance)
- 락을 쥔 스레드의 우선순위를, 기다리는 스레드 중 최고로 임시 상승
- L 이 H 의 우선순위로 돌아 빨리 끝내고 락을 놓는다
우선순위 상한(priority ceiling) 락마다 상한을 정하고, 잡는 순간 그 값으로 올린다
라이브락과 기아
- 데드락 — 서로 기다리며 아무도 진행 못 함 — 멈춰 있다
- 라이브락 — 서로 양보하며 계속 상태는 바뀌는데 진행이 없다
- (복도에서 마주쳐 같은 방향으로 계속 비켜서는 상황)
- 기아 — 우선순위가 낮아 영원히 자원을 못 받는다
- 에이징(대기 시간에 비례해 우선순위 상승) 으로 완화
왜 락 없이 만들어도 남는 문제인가
락을 안 쓰면 없어질 것 같지만 자원 공유 자체가 원인이다
-
메모리 할당자의 내부 락
-
로거의 뮤텍스
-
커널 자료구조의 락 (파일 · 소켓)
-
애플리케이션 코드에 락이 안 보여도 라이브러리·커널 안에 있다
-
실시간 시스템이 malloc 을 임계 경로에서 피하는 이유
우선순위 상속의 비용
- 장점 — 역전 구간이 짧아진다
- 단점 — · 우선순위 변경 자체가 스케줄러 연산이라 비용이 있다
- 중첩 락에서는 연쇄 상승이 일어나 추적이 복잡하다
- 상승된 스레드가 예상보다 오래 돌아 다른 태스크에 영향
리눅스는 pthread_mutexattr_setprotocol 로 PTHREAD_PRIO_INHERIT 를 켤 수 있다 기본값은 꺼져 있다 — 비용 때문이다
라이브락의 실제 사례
-
낙관적 락 재시도 — 두 트랜잭션이 서로를 감지하고 각자 롤백·재시도를 반복
- 지수 백오프 + 지터로 완화
-
이더넷 CSMA/CD — 충돌 감지 후 무작위 백오프를 쓰는 것도 같은 발상이다
- 고정 지연이면 다시 충돌한다
면접 함정
- ❌ "우선순위 역전은 데드락의 일종" → 진행은 하고 있다. 순서가 뒤집힐 뿐이다.
- ❌ "우선순위만 잘 주면 해결" → 락 소유 관계 때문에 생기므로 상속 기법이 필요하다.