높은 우선순위 태스크가 낮은 우선순위 태스크 때문에 실행되지 못하는 현상 (priority inversion).
어떻게 일어나는가
태스크 H(높음), M(중간), L(낮음)이 있고 H와 L이 뮤텍스를 공유한다.
- ① L이 뮤텍스를 획득하고 실행 중
- ② H가 준비됨 → L을 선점 → H 실행
- ③ H가 같은 뮤텍스를 요청 → L이 갖고 있으니 블로킹
- ④ L이 다시 실행 → 여기까지는 정상 (bounded inversion)
- ⑤ 그런데 M이 준비됨 → M이 L을 선점 ★
- ⑥ M이 실행되는 동안 L은 멈춤 → 뮤텍스를 못 놓음 → H도 계속 대기
★ 여기가 문제다. M은 뮤텍스와 아무 상관도 없는데, H보다 우선순위가 낮은 M이 H를 무한정 막고 있다.
- 우선순위: — H(1) > M(2) > L(3) 실제 실행: M이 H를 막는다 → 우선순위가 뒤집혔다
두 종류
- 제한된 역전(bounded) — : ④까지. L이 임계 구역을 끝내면 풀린다
- 예측 가능. 설계에 반영할 수 있다
- 무제한 역전(unbounded) — : ⑤ 이후. M이 계속 실행되면 H는 영원히 대기
- 데드라인을 놓친다. 진짜 문제
실제 사례 — 화성 탐사선 Pathfinder (1997)
착륙 후 며칠 뒤부터 시스템이 계속 리셋되기 시작
원인
- 정보 버스 관리 태스크(높음)와 기상 데이터 태스크(낮음)가
- 공유 버스 뮤텍스를 사용
- 통신 태스크(중간)가 끼어들어 우선순위 역전 발생
- 높은 태스크가 데드라인을 놓침
- 워치독이 시스템 이상으로 판단하고 리셋
해결
- 지구에서 원격으로 뮤텍스의 우선순위 상속 옵션을 켰다
- VxWorks에 기능은 있었지만 성능을 이유로 꺼 놓았던 것
임베디드 역사에서 가장 유명한 버그이며, 면접에서 종종 언급된다. "기능이 있어도 켜지 않으면 소용없다"는 교훈이기도 하다.
해결책 ① — 우선순위 상속
L이 H가 기다리는 뮤텍스를 갖고 있으면
→ L의 우선순위를 일시적으로 H와 같게 올린다
→ M이 L을 선점하지 못한다
→ L이 빨리 끝내고 뮤텍스를 놓는다
→ L의 우선순위를 원래대로 복원
FreeRTOS의 뮤텍스는 기본으로 우선순위 상속을 지원한다. (단, 세마포어는 지원하지 않는다 — 소유자 개념이 없기 때문이다.)
해결책 ② — 우선순위 상한 (priority ceiling)
- 뮤텍스마다 "이 뮤텍스를 쓰는 태스크 중 가장 높은 우선순위"를 미리 정해 둔다
- 뮤텍스를 잡는 순간 무조건 그 우선순위로 올린다
- 애초에 선점당하지 않는다
상속보다 강력하고 데드락도 방지하지만, 미리 분석이 필요하고 불필요하게 우선순위가 올라가는 구간이 생긴다.
해결책 ③ — 애초에 공유하지 않기
- 공유 자원 대신 메시지 큐로 소유권을 넘긴다
- 자원을 관리하는 전담 태스크를 두고, 다른 태스크는 요청만 보낸다
- 뮤텍스가 없으니 역전도 없다
가장 근본적인 해결이다. RTOS 설계에서 "공유 메모리보다 메시지"를 권하는 이유 중 하나다.
실무 체크리스트
✅ 세마포어가 아니라 뮤텍스를 쓴다 (상속 지원) ✅ FreeRTOS: configUSE_MUTEXES = 1 ✅ 임계 구역을 최대한 짧게 — 역전 시간이 곧 임계 구역 길이 ✅ 우선순위가 크게 다른 태스크끼리 자원을 공유하지 않도록 설계 ✅ 상속이 있어도 "제한된 역전"은 남는다 — 최악 시간 분석에 포함
우선순위 상속이 역전을 없애는 것이 아니다. 무제한을 제한된 것으로 바꿀 뿐이다. 여전히 L의 임계 구역 시간만큼은 H가 기다린다.
면접 답변 골격
"낮은 태스크가 잡은 자원을 높은 태스크가 기다릴 때, 중간 우선순위 태스크가 끼어들면 무제한 역전이 됩니다. 뮤텍스의 우선순위 상속으로 낮은 태스크를 일시적으로 올려 중간이 끼지 못하게 막습니다. Pathfinder 사고가 이 문제의 대표 사례입니다."