LiveLock이란 무엇인가? - Deadlock과의 차이 및 발생 원인, 예방 방법 정리
운영체제나 병렬 프로그래밍에서 자주 발생하는 동기화 문제로 Deadlock
은 널리 알려져 있지만, 이와 유사한 개념인 LiveLock
은 상대적으로 덜 알려져 있다. 이번 글에서는 LiveLock의 개념, 발생 원인, Deadlock과의 명확한 차이점 및 예방 전략까지 깊이 있게 다뤄본다.
LiveLock이란?
LiveLock
은 두 개 이상의 Process(혹은 Thread)가 상호작용하며 계속 상태 변화를 시도하지만, 실제로는 어떤 작업도 진행되지 않는 상태를 의미한다. Deadlock과 달리 프로세스들이 “정지된 상태”가 아니라 끊임없이 상태를 변경하며, 형식상 CPU를 계속 소비하는 특징이 있다.
즉, Deadlock은 프로세스들이 서로 자원을 기다리며 정지 상태로 멈춰있는 반면, LiveLock은 Process들이 바쁘게 움직이고 있지만 결과적으로는 전혀 진전이 없다.
Deadlock과의 구체적 차이점
Deadlock과 LiveLock의 근본적인 차이는 다음과 같다.
특징 | Deadlock | LiveLock |
---|---|---|
상태 | 대기(waiting) 상태로 정지 | 지속적(active) 상태 변화 |
CPU 점유 여부 | CPU 사용 거의 없음 | CPU 지속 사용 |
상태 변화 여부 | 변화 없음 (정체 상태) | 지속적 변화 (진행 없는 무한반복) |
진전 가능성 | 없음 | 표면상 존재하지만 실제 없음 |
Deadlock은 정적이고 명확한 대기 상태지만, LiveLock은 동적으로 움직이면서도 진행되지 않는다는 점에서 더욱 탐지 및 디버깅이 까다롭다.
LiveLock의 구체적 발생 원인과 실제 사례
LiveLock의 대표적인 발생 원인은 다음과 같다.
동시에 동일한 전략으로 충돌 해결 시도
두 스레드가 충돌을 인지하고 동시에 후퇴(back-off)하거나 재시도(retry)를 반복하면, 무한히 같은 행동을 반복하여 서로 간섭한다.지속적인 rollback과 retry
트랜잭션 시스템에서 여러 트랜잭션이 충돌시 rollback하고 다시 실행을 반복하면서 아무것도 완료하지 못하는 상황이다.
LiveLock을 재현한 실제 코드 예시 (C#)
다음 예제는 두 스레드가 서로의 충돌을 인지하고 동일한 후퇴(back-off) 전략을 반복적으로 사용하여 LiveLock을 발생시키는 간략한 예시이다.
예시 코드:
1 | using System; |
위 코드에서 두 스레드는 각각 하나의 자원을 점유한 상태에서 상대 자원을 얻지 못하면 점유한 자원을 반환하고 다시 시도한다. 이 과정이 정확히 교차하면 무한 반복이 발생하여 LiveLock 상태에 빠질 수 있다.
LiveLock 예방 전략
LiveLock 예방을 위한 일반적인 방법은 다음과 같다.
1. 무작위 지연 전략(randomized back-off)
충돌이 발생했을 때, 동일한 간격으로 재시도하지 않고 랜덤한 시간만큼 기다린 뒤 재시도하여 충돌 가능성을 낮춘다.
2. 우선순위 부여
충돌 발생 시 일정한 우선순위를 부여해 우선순위가 낮은 스레드가 먼저 양보하도록 강제한다.
3. Exponential Back-off (지수적 증가 후퇴 전략)
재시도 간격을 충돌 발생 횟수에 따라 지수적으로 증가시켜 충돌 확률을 현저히 줄인다.
요약 및 결론
- LiveLock은 Process가 지속적으로 상태를 변화시키지만 실제로는 작업이 전혀 진행되지 않는 병렬 프로그래밍의 동기화 문제다.
- Deadlock은 정지 상태를 유지하며, LiveLock은 지속적으로 CPU 자원을 소모하는 차이가 있다.
- LiveLock은 동일한 충돌 회피 전략의 반복, 지속적인 retry가 주원인이며, 무작위적 또는 지수적으로 증가하는 back-off, 우선순위 전략으로 예방 가능하다.
LiveLock은 Deadlock만큼 자주 언급되진 않지만, 실제 운영환경에서 발생하면 탐지와 해결이 어려워 큰 성능 문제를 일으킬 수 있다. 따라서 병렬 프로그래밍을 수행할 때는 Deadlock 뿐만 아니라 LiveLock 역시 주의하여 설계할 필요가 있다.