동기화는 멀티 프로세스 또는 멀티 스레드 환경에서 여러 주체가 공유 자원(Shared Resource)에 동시에 접근할 때, 데이터의 일관성(Consistency)과 무결성(Integrity)을 유지하도록 접근 순서를 제어하는 것
즉, 공유 자원에 동시에 접근하여 예상치 못한 결과를 초래하는 경쟁 상태(Race Condition)를 방지하는 것이 주된 목적
임계 구역(Critical Section)이란 둘 이상의 프로세스/스레드가 공유 데이터(변수, 파일 등)에 접근하고 변경하는 코드 영역
Critical Section 문제는 여러 프로세스가 동시에 임계 구역에 진입하여 공유 데이터를 변경하려 할 때 발생할 수 있는 데이터 불일치 문제를 해결하는 것
이 문제를 해결하기 위해서는 다음 세 가지 조건이 보장되어야 한다.
이들은 Critical Section 문제를 해결하기 위한 대표적인 동기화 도구(Synchronization Tools)
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 1. 뮤텍스 객체 선언 및 초기화
...
do {
pthread_mutex_lock(&mutex); // 2. Lock 획득 시도: 성공 시 임계 구역 진입, 실패 시 Lock 해제될 때까지 대기 상태(Block) 전환
...
//critical section // 3. 임계 구역: Lock을 획득한 하나의 스레드/프로세스만 실행
...
pthread_mutex_unlock(&mutex); // 4. Lock 반납: 임계 구역 작업 후, Lock 해제
}
P(wait)와 V(signal) 연산을 사용sem_t semaphore;
sem_init(&semaphore, 0, 3); // 1. 공유 가능한 자원을 수 3으로 초기화
...
do {
sem_wait(&semaphore); // 2. P() 연산: 자원 획득, 카운트 감소
...
//critical section
...
sem_post(&semaphore); // 3. V() 연산: 자원 반납, 카운트 증가
}
class ResourceManager {
private int availableResources = 3; // 공유 자원
// 메서드 전체에 Lock을 걸어 상호 배제를 보장
public synchronized void acquireResource(int needed) throws InterruptedException {
// [자동 Lock 획득] - 메서드 진입 시 자동
// 2. 조건 대기 (Condition Wait)
while (availableResources < needed) {
// 자원이 부족하면 대기 큐로 이동. Lock을 반납함.
this.wait();
}
// 조건 충족: 자원 사용
availableResources -= needed;
// [자동 Lock 해제] - 메서드 종료 시 자동
}
public synchronized void releaseResource(int amount) {
// [자동 Lock 획득] - 메서드 진입 시 자동
// 자원 반납
availableResources += amount;
// 대기 중인 스레드 깨우기
// wait() 상태인 스레드 중 하나를 깨워 경쟁하도록 함 (모니터의 signal() 역할)
this.notify(); // 또는 this.notifyAll();
// [자동 Lock 해제] - 메서드 종료 시 자동
}
}
| 구분 | 뮤텍스 (Mutex) | 세마포어 (Semaphore) | 모니터 (Monitor) |
|---|---|---|---|
| 개념 | 상호 배제(Mutual Exclusion)를 위한 잠금(Lock) 메커니즘. | 신호 메커니즘을 사용하는 동기화 도구. 공유 자원에 접근 가능한 프로세스/스레드의 수를 정수 변수로 관리. | 공유 자원과 이에 접근하는 프로시저(함수)들을 하나로 묶어 상호 배제를 달성하는 고급 동기화 구조체. |
| 자원 수 | 동기화 대상이 1개일 때 사용 (Binary Semaphore와 유사). | 동기화 대상이 1개 이상일 때 사용 (Counting Semaphore). 1개일 경우 이진 세마포어. | 일반적으로 공유 자원을 보호하며 상호 배제를 보장. |
| 소유 | Lock을 획득한 (소유한) 스레드/프로세스만이 Lock을 해제(반납)할 수 있음. | Lock을 소유하지 않은 스레드/프로세스도 Signal(V 연산)을 통해 자원 사용 가능 수를 증가시킬 수 있음. | 내부적으로 상호 배제를 자동 보장하며, 조건 변수(Condition Variable)를 통해 복잡한 동기화를 처리. |
| 구현 | Lock/Unlock (또는 Wait/Signal의 일종) 연산을 사용. | P() (Wait, 감소)와 V() (Signal, 증가) 두 가지 원자적(Atomic) 연산을 사용. | 컴파일러가 상호 배제를 처리해주므로, 사용자가 직접 Lock/Unlock 관리를 할 필요가 적어 오류 발생 가능성이 낮음. |
교착 상태(Deadlock)란 둘 이상의 프로세스가 서로 상대방이 점유하고 있는 자원을 기다리면서, 무한히 대기하는 상태. 이 상태에 빠진 프로세스는 더 이상 작업을 진행할 수 없다.
교착 상태가 발생하기 위해서는 다음 네 가지 조건이 모두 동시에 충족되어야 한다.
교착 상태를 해결하는 접근 방식은 크게 네 가지이다.
| 해결 방법 | 설명 |
|---|---|
| Deadlock 예방 (Prevention) | 교착 상태 발생 조건 4가지 중 하나 이상을 부정하여 교착 상태가 애초에 발생하지 않도록 합니다. (예: 자원을 한 번에 모두 할당, 선점 허용 등) |
| Deadlock 회피 (Avoidance) | 자원 요청 시 시스템을 안전 상태(Safe State)로 유지할 수 있는 경우에만 자원을 할당합니다. 대표적으로 은행원 알고리즘 (Banker's Algorithm) |
| Deadlock 탐지 및 회복 (Detection & Recovery) | 교착 상태 발생을 허용하되, 주기적으로 교착 상태를 탐지하고, 발생하면 강제로 프로세스를 종료하거나 자원을 선점하여 교착 상태에서 벗어남 |
| Deadlock 무시 (Ignorance) | 교착 상태가 매우 드물게 발생한다고 가정하고, 운영체제가 아무런 조치도 취하지 않는 방식 (가장 일반적인 접근 방식) |
+자료에 따라 교착상태 복구 (recovery)를 4번째 방법으로 정리함
Deadlock 복구 (Recovery) = 교착 상태를 일으킨 프로세스를 종료하거나 할당된 자원을 해제시키는 방법.
정리된 표가 있어서 비교하면서 이해하기 좋았어요!