Monitor
프로세스 동기화에서 **모니터(Monitor)**는 공유 자원에 대한 안전한 접근을 보장하기 위한 상위 수준의 동기화 도구이다.
모니터는 공유 데이터와 해당 데이터를 조작하는 연산을 하나의 모듈로 캡슐화하여, 다중 스레드 환경에서의 경쟁 조건(Race Condition)을 방지한다.
모니터는 고수준의 동기화 추상화로, 복잡한 뮤텍스/세마포어 관리 없이 안전한 병행 프로그래밍을 가능하게 한다.
현대 언어에서는 모니터 패턴이 내장되어 있어(synchronized
, lock
), 데드락과 경쟁 조건을 효과적으로 방지한다.
다만 저수준 시스템 프로그래밍에서는 뮤텍스나 세마포어가 더 유연할 수 있다.
정의
모니터는 **뮤텍스(Mutex)**와 **조건 변수(Condition Variable)**를 결합한 추상화된 동기화 메커니즘이다.
- 뮤텍스: 모니터 내부에서 한 번에 하나의 스레드만 진입하도록 보장한다.
- 조건 변수: 특정 조건이 충족될 때까지 스레드를 대기시키거나 알림을 보낸다(
wait()
및signal()
).
구성 요소
모니터는 다음과 같은 요소로 구성된다:
- 공유 데이터: 여러 스레드가 접근하는 변수.
- 모니터 프로시저(Procedure): 공유 데이터를 조작하는 메서드.
- 초기화 코드: 모니터 생성 시 데이터 초기화.
- 진입 큐(Entry Queue): 모니터 진입 대기 스레드의 큐.
- 조건 변수 큐:
wait()
호출로 대기하는 스레드의 큐 (예:notEmpty
,notFull
).
|
|
모니터의 동작 원리
상호 배제(Mutual Exclusion)
모니터 내부에서는 한 번에 하나의 스레드만 실행된다.
다른 스레드는 진입 큐에서 대기한다.조건 변수(Condition Variable)
wait()
: 조건이 충족되지 않으면 스레드를 대기 상태로 전환하고 모니터 락을 해제한다.signal()
: 대기 중인 스레드 하나를 깨워 실행을 재개한다.
모니터의 장단점
장점
- 캡슐화: 공유 데이터와 동기화 로직을 하나의 모듈로 통합.
- 안전성: 뮤텍스와 조건 변수를 직접 사용하는 것보다 오류 가능성이 낮음.
- 간결성: 세마포어보다 직관적인 코드 작성 가능.
단점
- 언어 의존성: Java, C# 등 특정 언어에서만 지원.
- 컴파일러 부담: 모니터 구현을 위해 컴파일러가 추가 작업 필요.
모니터의 실제 구현 예시
생산자-소비자 문제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class BoundedBuffer: def __init__(self, size): self._monitor = threading.RLock() self._not_full = threading.Condition(self._monitor) self._not_empty = threading.Condition(self._monitor) self.buffer = collections.deque(maxlen=size) def produce(self, item): with self._monitor: while len(self.buffer) == self.buffer.maxlen: self._not_full.wait() self.buffer.append(item) self._not_empty.notify() def consume(self): with self._monitor: while len(self.buffer) == 0: self._not_empty.wait() item = self.buffer.popleft() self._not_full.notify() return item
읽기-쓰기 문제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
class ReadWriteMonitor: def __init__(self): self._monitor = threading.Lock() self._no_readers = threading.Condition(self._monitor) self._no_writers = threading.Condition(self._monitor) self.readers = 0 self.writers = 0 def start_read(self): with self._monitor: while self.writers > 0: self._no_writers.wait() self.readers += 1 def end_read(self): with self._monitor: self.readers -= 1 if self.readers == 0: self._no_readers.notify() def start_write(self): with self._monitor: while self.readers > 0 or self.writers > 0: self._no_readers.wait() self._no_writers.wait() self.writers += 1 def end_write(self): with self._monitor: self.writers -= 1 self._no_writers.notify_all()
Java의
synchronized
synchronized
키워드로 메서드 전체를 동기화.
C#의
Monitor
클래스Enter()
와Exit()
으로 명시적 락 관리.