본문 바로가기
카테고리 없음

Deadlock(교착상태)은 왜 발생할까

by by_merry 2026. 5. 20.

멀티스레드와 동시성(concurrency) 구조를 공부하다 보면 생각보다 “속도를 높이는 것”보다 “충돌을 막는 것”이 훨씬 더 어려운 문제처럼 느껴질 때가 많다. 나도 처음에는 CPU 코어가 많아지고 스레드가 많아질수록 무조건 성능이 좋아질 거라고 생각했었다. 그런데 실제로는 여러 작업이 동시에 움직이는 순간부터 프로그램 구조가 엄청 복잡해지기 시작했고, 그 과정에서 등장하는 대표적인 문제가 바로 Deadlock, 즉 교착상태였다.

처음 이 단어를 들었을 때는 그냥 프로그램이 멈추는 현상 정도로만 생각했다. 그런데 구조를 이해하고 나니까 단순 오류라기보다는, 여러 작업이 서로를 기다리다가 영원히 멈춰버리는 상황에 더 가까웠다. 특히 재미있었던 건, 이게 단순히 코드 실수라기보다 “동시에 안전하게 처리하려고 만든 구조” 때문에 오히려 발생할 수 있다는 점이었다.

 

Deadlock은 서로 자원을 기다리면서 영원히 멈추는 상황이다

Deadlock은 보통 여러 스레드가 서로가 가진 자원을 기다릴 때 발생한다. 쉽게 말하면 “너 먼저 끝나면 나도 진행할게” 상태가 서로 반복되는 것이다.

예를 들어 스레드 A는 자원 1을 이미 사용 중인데 자원 2가 추가로 필요하다. 반대로 스레드 B는 자원 2를 사용 중인데 자원 1이 필요하다면 어떻게 될까?

둘 다 서로 상대방이 가진 자원을 기다리게 된다. 문제는 아무도 먼저 자원을 놓지 않으면 상황이 영원히 끝나지 않는다는 점이다.

나도 처음에는 “운영체제가 알아서 해결해주는 거 아닌가?” 싶었는데, 실제로는 프로그램 구조 자체가 잘못 설계되면 운영체제도 자동으로 해결하기 어려운 경우가 많다고 한다.

특히 이 개념을 처음 이해할 때 가장 기억에 남았던 건 식당 비유였다. 예를 들어 두 사람이 각각 포크와 나이프 하나씩 들고 있는데, 둘 다 상대방이 가진 도구를 기다리면서 아무도 놓지 않는 상황과 비슷하다는 설명이었다. 그걸 듣고 나니까 왜 이름이 교착상태(Deadlock)인지 바로 이해가 됐다.

결국 Deadlock은 단순히 프로그램이 느려지는 수준이 아니라, 특정 작업 흐름 자체가 완전히 멈춰버리는 문제에 가까운 것이다.

락(Lock)을 사용할수록 Deadlock 위험도 커질 수 있다

Race Condition을 막기 위해 프로그래밍에서는 Lock이나 Mutex 같은 동기화 구조를 많이 사용한다. 쉽게 말하면 어떤 스레드가 데이터를 수정하는 동안 다른 스레드 접근을 잠시 막는 방식이다.

처음에는 나도 “그럼 락 많이 쓰면 안전한 거 아닌가?”라고 생각했다. 실제로 락을 사용하면 동시에 같은 데이터를 수정하는 문제는 꽤 잘 막을 수 있다.

그런데 문제는 락이 많아질수록 스레드끼리 서로 기다리는 상황도 늘어난다는 점이었다. 특히 여러 개의 락을 동시에 사용하는 구조에서는 Deadlock 위험이 훨씬 커진다.

예를 들어 스레드 A는 먼저 Lock 1을 잡고 Lock 2를 기다리고 있는데, 스레드 B는 Lock 2를 잡고 Lock 1을 기다리는 상황이 생길 수 있다. 이 순간부터 둘은 서로 영원히 대기하게 된다.

나도 예전에 간단한 멀티스레드 예제를 보면서 “락이 안전을 보장해주는 만능 도구인 줄 알았는데, 오히려 새로운 문제도 만드는구나”라는 걸 느꼈다. 특히 서버 프로그램처럼 수많은 스레드가 동시에 움직이는 환경에서는 락 구조 자체가 엄청 중요한 설계 문제가 된다고 한다.

그래서 실제 서버 개발에서는 “어떤 순서로 락을 잡을지”까지 규칙을 정하는 경우도 많다고 한다. 단순히 코드를 잘 짜는 수준을 넘어, 시스템 전체 흐름을 고려해야 하는 것이다.

Deadlock이 무서운 이유는 발견도 어렵고 시스템 전체를 멈출 수 있기 때문이다

Deadlock이 특히 무서운 이유는 항상 바로 드러나는 문제가 아니라는 점이다. 어떤 환경에서는 잘 동작하다가도 특정 타이밍에서만 갑자기 멈출 수 있다.

나도 처음에는 “프로그램이 멈추면 금방 원인 찾을 수 있는 거 아닌가?” 싶었는데, 실제로는 멀티스레드 환경에서 Deadlock 원인을 찾는 게 굉장히 어렵다고 한다. 특히 실행 순서가 조금만 달라져도 문제가 안 나타날 수도 있기 때문이다.

실제로 서버 장애 사례들을 보면 Deadlock 때문에 서비스 전체가 응답하지 않게 되는 경우도 꽤 많았다. CPU 사용률은 높지 않은데 요청 처리가 멈추는 이상한 상황이 발생하고, 알고 보니 내부에서 스레드들이 서로 락을 기다리면서 전부 멈춰 있었던 것이다.

그걸 보면서 처음으로 “동시성 문제는 단순 버그 수준이 아니라 시스템 안정성 자체와 연결되는구나”라는 걸 느끼게 됐다.

특히 현대 프로그램은 멀티코어 CPU와 병렬 처리 구조 위에서 계속 발전하고 있기 때문에, 단순히 빠르게 만드는 것보다 “동시에 움직이는 작업들을 얼마나 안전하게 제어할 수 있느냐”가 점점 더 중요한 문제가 되고 있다는 생각도 들었다.

한 줄로 정리하면 Deadlock은 여러 스레드가 서로가 가진 자원을 기다리면서 아무도 작업을 진행하지 못하는 상태이며, 동시성 환경에서 시스템 전체를 멈출 수도 있는 위험한 문제다.