멀티스레드 환경에서는 여러 프로세스나 스레드가 동시에 실행되면서 자원을 공유하는 일이 많습니다. 하지만 잘못된 동기화 기법이나 자원 관리로 인해 교착 상태(Deadlock)가 발생하거나, 스레드 안전(Thread Safe)이 보장되지 않는 문제가 생길 수 있습니다.
이 글에서는 교착 상태의 개념과 발생 조건, 해결 방법을 알아보고, 스레드 안전성을 유지하는 방법을 정리해 보겠습니다.
교착 상태(Deadlock)란?
교착 상태란, 둘 이상의 프로세스가 서로의 자원을 기다리며 무한히 멈춰 있는 상태를 의미합니다.
즉, 프로세스 A는 프로세스 B가 가진 자원을 기다리고, 프로세스 B는 다시 프로세스 A가 가진 자원을 기다리는 상황이 발생하여 더 이상 진행할 수 없는 상태가 되는 것입니다.
✅ 교착 상태 발생 조건 (4가지 필요 충분 조건)
교착 상태는 다음 4가지 조건이 모두 충족될 때 발생합니다.
- 상호 배제 (Mutual Exclusion)
- 하나의 공유 자원에 대해 한 번에 하나의 프로세스만 접근할 수 있는 경우
- 예: 프린터를 여러 프로세스가 동시에 사용할 수 없도록 설정됨
- 점유와 대기 (Hold and Wait)
- 프로세스가 이미 하나 이상의 자원을 점유한 상태에서 추가 자원을 요청하며 대기하는 경우
- 예: 프로세스 A가 프린터를 점유하고, 추가로 USB 자원을 기다리는 상황
- 비선점 (Non-Preemption)
- 이미 할당된 자원을 강제로 해제할 수 없는 경우
- 예: 프로세스 B가 사용 중인 파일을 다른 프로세스가 강제로 가져올 수 없음
- 환형 대기 (Circular Wait)
- 프로세스 간에 자원을 기다리는 사이클이 형성된 경우
- 예: 프로세스 A → 프로세스 B → 프로세스 C → 프로세스 A 형태로 자원을 기다림
💡 교착 상태를 해결하려면?
위 4가지 조건 중 하나라도 제거하면 교착 상태를 예방할 수 있습니다.
예를 들어, ‘비선점’을 없애려면 자원을 일정 시간 동안 사용하지 않으면 자동으로 해제하는 방식을 적용할 수 있습니다.
스레드 안전(Thread Safe)이란?
멀티 스레드 환경에서 여러 개의 스레드가 동시에 하나의 변수, 함수, 객체에 접근해도 문제가 발생하지 않는 것을 의미합니다.
하지만, 스레드 안전하지 않은 경우, 다음과 같은 단순한 코드에서도 예상치 못한 오류가 발생할 수 있습니다.
var++;
위 연산이 실행되는 과정은 다음과 같습니다.
- var 값을 CPU 레지스터로 로드
- var++ 연산 수행
- 연산된 값을 메모리에 저장
하지만 두 개 이상의 스레드가 동시에 var++을 실행하면 다음과 같은 문제가 발생합니다.
스레드1: var을 CPU 레지스터로 로드 (var: 0)
스레드1: var++ 수행 (var: 1)
스레드1: var을 메모리에 저장 (var: 1)
스레드2: var을 CPU 레지스터로 로드 (var: 1)
스레드2: var++ 수행 (var: 2)
스레드2: var을 메모리에 저장 (var: 2)
즉, 두 개의 스레드가 같은 변수에 접근하면서 값이 덮어씌워지는 문제가 발생합니다.
이러한 문제를 방지하려면 스레드 안전한 기법을 사용해야 합니다.
스레드 안전을 위한 4가지 조건
- 상호 배제 (Mutual Exclusion)
- 뮤텍스(Mutex), 세마포어(Semaphore) 등을 이용해 공유 자원 접근을 제한
- 예: std::mutex를 이용한 임계 구역 보호
- 원자 연산 (Atomic Operation)
- 연산 도중 다른 스레드가 접근할 수 없도록 보장
- 예: C++의 std::atomic을 활용하여 var++을 원자적으로 실행
- 재진입성 (Reentrancy)
- 동일한 함수를 여러 스레드가 호출해도 문제가 없도록 구현
- 예: static 변수 사용 지양, malloc 대신 스레드 안전한 할당 함수 사용
- 스레드 지역 저장소 (Thread Local Storage, TLS)
- 각 스레드에서만 접근할 수 있는 저장소 사용
- 예: thread_local 키워드를 사용하여 데이터 충돌 방지
마무리
멀티 스레드 프로그래밍에서는 교착 상태(Deadlock)와 스레드 안전(Thread Safe) 문제를 항상 고려해야 합니다.
✔ 교착 상태를 방지하려면?
→ 4가지 필요 충분 조건 중 하나를 제거!
✔ 스레드 안전을 유지하려면?
→ 뮤텍스, 원자 연산, 재진입성, TLS 등의 기법 활용!
멀티 스레드 환경에서 안정적인 프로그램을 만들기 위해서는 교착 상태를 예방하고, 스레드 안전한 코드 작성을 습관화하는 것이 필수입니다.
해당 글은 다음 도서의 내용을 참고하고 추가적인 정보를 기재한 글임을 밝힙니다.
이수진, ⌜기술면접대비 CS전공 핵심요약집⌟, (주)도서출판 길벗
'CS지식 > 운영체제' 카테고리의 다른 글
IPC(Inter Process Communication), 좀비 프로세스, 고아 프로세스 (0) | 2025.02.04 |
---|---|
프로세스 동기화 (0) | 2025.02.01 |
동시성과 병렬성, 멀티 프로세스와 멀티 스레드 (0) | 2025.01.31 |
PCB(Process Control Block), 프로세스의 생성, 프로세스 상태도 (0) | 2025.01.30 |
프로세스, 메모리 구조 (0) | 2024.11.05 |