프로세스 동기화의 고전적인 문제
- Bounded Buffer (Producer-Consumer Problem, 유한 버퍼 문제)
생산자와 소비자가 공유 버퍼를 사용할 때 발생하는 동기화 문제.
→ 버퍼가 가득 찼을 때 생산자는 대기, 버퍼가 비었을 때 소비자는 대기해야 한다. - Reader-Writer Problem (독자-저자 문제)
여러 프로세스가 같은 데이터베이스에 접근할 때 발생.
→ 여러 Reader는 동시에 접근 가능하지만, Writer는 단독으로 접근해야 한다. - Dining Philosophers Problem (식사하는 철학자 문제)
여러 프로세스가 한정된 자원(포크)을 공유하면서 교착 상태나 기아 상태 없이 자원을 사용하는 문제.
동기화 문제 해결에 사용되는 도구들
Mutex / Lock | 상호 배제를 보장하는 가장 기본적인 동기화 도구 |
Semaphore | 정수 값을 이용해 대기/신호 방식을 구현, 제한된 수의 자원을 제어 |
Monitor | 고수준 동기화 도구. 공유 데이터와 연산, 동기화를 하나의 추상화된 구조로 캡슐화 예) Java: synchronized 키워드, wait(), notify(), notifyAll() |
Condition Variable | 모니터 내부에서 특정 조건이 충족될 때까지 대기/신호를 구현하는 메커니즘 |
Mutex
- Mutual Exclusion의 줄임말 → “상호 배제”
- 한 번에 하나의 프로세스/스레드만 임계구역에 들어갈 수 있도록 보장하는 동기화 도구
- Lock/Unlock 연산을 제공
- lock: 임계구역에 들어가기 전에 획득 (이미 누가 가지고 있으면 대기)
- unlock: 임계구역에서 나오면서 반환
Mutex 동작 방식
- 스레드 A가 mutex.lock() 호출 → lock 획득, 임계구역 진입
- 스레드 B가 mutex.lock() 시도 → A가 사용 중이므로 B는 block 상태로 대기
- 스레드 A가 mutex.unlock() 호출 → lock 해제
- 스레드 B가 lock을 얻고 임계구역 진입
즉, mutex는 임계구역 진입을 직렬화(serialization) 해서 경쟁 조건을 방지합니다.
Semaphore
공유 자원의 개수를 세는 카운터
Semaphore의 종류
- Binary Semaphore (이진 세마포어)
- 값이 0 또는 1만 가짐.
- 사실상 Mutex와 유사, 단 소유권 개념이 없음. (누구든 signal 가능)
- Counting Semaphore (카운팅 세마포어)
- 값이 0 이상인 정수.
- 동일 자원이 여러 개 있을 때 사용.
- 예: 5개의 DB 연결 풀 → 세마포어 초기값 5로 설정.
Semaphore 동작 방식
초기 세마포어 값: S.value = 1
- 스레드 A: wait(S) 실행
- S.value = 0 → 자원 획득 성공 → 임계구역 진입
- 스레드 B: wait(S) 실행
- S.value = -1 → 음수 됨 → 자원 없음 → B는 waitQueue에 들어가고 block 상태
- 스레드 A: 임계구역 끝나고 signal(S) 실행
- S.value = 0 → waitQueue에 있던 B를 깨움 → B가 자원 얻고 실행
운영체제별 접근 방식
Windows
Dispatcher Object | 프로세스/스레드 동기화를 위한 기본 커널 오브젝트 |
Event | 특정 조건이 발생했음을 알리고 다른 스레드가 이를 기다렸다가 동작할 수 있게 함 |
Linux
원자적 변수(Atomic Variable) | CPU 명령 단위로 동작, 경쟁 조건 방지 |
Spinlock | 짧은 임계 구역 보호 시 사용, 바쁜 대기 방식 |
Mutex Lock | 커널 수준에서 구현된 상호 배제 도구 |
임계 구역 문제에 대한 대안적 접근
Transactional Memory | 메모리 접근을 트랜잭션 단위로 실행, 충돌 시 자동 롤백. 프로그래머가 명시적으로 락을 다루지 않아도 됨. |
OpenMP | 병렬 프로그래밍을 위한 API. 컴파일러 지시어를 통해 간단히 동기화를 처리. |
Functional Languages | 상태를 유지하지 않는 불변성(immutability)을 기반으로 하므로 경쟁 조건에 본질적으로 안전. 예: Haskell, Erlang. 동시성 모델이 절차적 언어와 다름 (ex. 메시지 전달 기반). |
즉, 고전적인 문제(유한 버퍼, Reader-Writer, Dining Philosophers)는 동기화 도구(Mutex, Semaphore 등)를 통해 해결할 수 있고, OS마다 이를 구현하는 방식(Windows Dispatcher Object, Linux Mutex 등)이 다르며, 더 나아가 함수형 언어나 트랜잭션 메모리 같은 언어적/모델적 대안도 존재한다는 게 핵심