왜 모니터(Monitor)를 사용하는가?
세마포는 프로세스간 동기화를 위해 편리하고 효율적으로 쓰일 수 있지만 잘못 사용하면 timing error를 발생시킬 수 있다.
timing error는 특정한 순서로 실행되었을 때만 발생하기 때문에 발견이 어렵다.
mutex lock과 세마포는 이러한 오류를 해결하기 위해서 도입되었지만, 다음과 같은 상황에서 오류가 발생할 수 있다.
1. wait(mutex)와 signal(mutex) 연산의 순서가 뒤바뀌었을 때,
여러 프로세스가 임계구역에 동시에 진입했을 때 문제가 발생한다.
2. signal(mutex)를 써야 할 곳에 wait(mutex)를 썼을 때,
두 번째 wait(mutex) 연산에서 교착 상태가 발생한다.
3. wait(mutex)나 signal(mutex)가 누락되었을 때, 프로세스는 영원히 block 된다.
이처럼 프로그래머가 세마포나 mutex lock을 잘못 사용하면 오류가 쉽게 발생한다.
이를 해결하기 위한 한 가지 전략은 간단한 동기화 도구들을 통합아여 고급 언어 구조물을 제공하는 것이다.
모니터는 고급 언어 구조물 중 하나이다.
모니터 사용법(Monitor Usage)
Abstract Data Type(ADT)는 특정 구현과는 무관한 데이터와 이 데이터를 조작하는 함수들의 집합을 캡슐화한다.
모니터의 type은 ADT이다.
이는 모니터에서 상호 배제가 보장되는 프로그래머가 정의한 일련의 연산자 집합을 포함한다.
이는 instance state를 정의한 변수와 그 변수들을 조작할 수 있는 함수들의 본체를 선언한다.
모니터 type은 프로세스가 직접 사용할 수 없다.
모니터 내부의 함수는 내부에 정의된 변수와 parameter에 의해서만 접근할 수 있고,
모니터 내부의 local 변수는 local 함수에 의해서만 접근할 수 있다.
모니터 구조는 모니터 내에서 한번에 한 프로세스만 활성화되도록 보장해준다.
따라서 프로그래머들은 동기화 제약 조건을 명시적으로 코딩해야 할 필요가 없다.
하지만 지금까지 정의한 모니터 구조는 충분한 능력을 제공하지 않기 때문에 추가적인 동기화 기법을 정의해야 한다.
이 동기화 기법들은 condition이라는 구조로 제공된다.
프로그래머는 condition type 변수를 정의할 수 있고, 이 변수에 호출될 수 있는 연산은 wait()와 signal()이다.
condition 변수 x에 대해서,
x.wait()는 이 연산을 호출한 프로세스는 다른 프로세스가 x.signal()을 호출할 때까지 일시 중지 되어야 한다는 것을 의미한다.
x.signal()은 정확히 하나의 일시 중지 프로세스를 재개한다.
따라서 일시 중지된 프로세스가 없으면 아무런 영향이 없다.
x.signal()이 프로세스 P에 의해서 호출될 때, 조건 x와 연관된 일시 중지된 프로세스 Q가 있다고 가정하면,
일시 중지된 프로세스 Q가 재개되면, signal을 보낸 프로세스 P는 반드시 wait 해야 한다.
그렇지 않으면, 두 프로세스 P와 Q가 동시에 활성화된다.
하지만 두 프로세스는 개념적으로 그들의 실행을 계속할 수 있다.
여기에는 두 가지 가능성이 존재한다.
1. signal and wait:
P는 Q가 모니터를 떠날 때까지 기다리거나 또는 다른 조건을 기다린다.
2. signal and continue:
Q는 P가 모니터를 떠날 때까지 기다리거나 또는 다른 조건을 기다린다.
이 두 가지 선택의 절충안도 존재한다.
P가 signal() 연산을 실행하면 즉시 모니터를 떠나고, Q가 즉시 재개된다.
세마포를 이용한 모니터의 구현
세마포를 이용해서 모니터 기법을 구현할 수 있다.
각 모니터마다 mutex라는 이진 세마포가 정의되고, 1로 초기화한다.
프로세스는 모니터로 들어가기 전에 wait(mutex)를 실행하고, 모니터를 나온 후에는 signal(mutex)를 실행한다.
모니터를 구현할 때 signal-and-wait 기법을 사용할 것이다.
signaling 프로세스는 실행 재개되는 프로세스가 모니터를 떠나거나 wait() 할 때까지 기다려야 하므로,
next라는 이진 세마포가 추가로 필요하고 0으로 초기화된다.
또한 next에서 일시 중지되는 프로세스의 개수를 세기 위한 정수형 변수 next_count가 제공된다.
condition 변수는 각 조건 x 마다 x_sem이라는 이진 세마포와 x_count라는 정수형 변수를 도입하고 둘 다 0으로 초기화 한다.
x.wait() 연산과 x.signal() 연산은 다음과 같이 구현된다.
세마포는 signal시 wait로 대기중인 여러 프로세스가 반응하는 반면,
모나터는 signal시 모니터 내 x에 대해 큐에서 대기중인 프로세스만 반응한다.
모니터 내에서 프로세스 수행 재개
조건 변수 x에 여러 프로세스가 일시 중지 되어 있고, 어떤 프로세스가 x.signal() 연산을 수행했다고 하면, 일시 중지 되었던 프로세스 중 어느 프로세스가 재개될 것인지를 결정해야 한다.
한 가지 간단한 방법은 FSFC를 사용하는 것이다.
이는 가장 오래 기다렸던 프로세스가 깨어나는 것이다.
하지만 이러한 간단한 스케줄링 기법으로는 충분하지 않을 경우, conditional-wait 구조를 사용할 수 있다.
이는 x.wait(c)의 형태를 가지는데, 여기서 c는 우선순위 번호로 일시 중지 되는 프로세스의 이름과 함께 저장된다.
x.signal() 연산 시 가장 작은 우선순위 번호를 가지는 프로세스가 수행을 재개하게 된다.
이 기법의 예시로는 ResourceAllocator 모니터가 있는데, 이는 자원을 요청할 때 사용시간을 명시해서
가장 짧은 시간을 요청한 프로세스에 자원을 할당해준다.
모니터에서도 timing error가 발생할 수 있다.
프로세스가 자원에 대한 허락을 받지 않고 접근하거나, 접근 후 해제를 하지 않거나, 요청하지 않은 자원을 해제하거나, 자원을 해제하지 않고 동일한 자원을 두 번 요청하는 등의 문제가 발생한다.
이를 해결하기 위한 한 가지 방법은 모니터 내에 자원 접근 연산을 포함시키는 것이다.
프로세스들이 올바른 순서를 지키도록 보장하기 위해서는 모니터와 모니터가 관리하는 자원을 사용하는 모든 프로그램들을 검사하여야 한다.
하지만 이는 규모가 큰 프로그램이나 동적인 시스템에서는 비합리적이다.
이는 접근 제어 기법들을 사용해서 해결할 수 있다.
'전공 > 운영체제' 카테고리의 다른 글
[운영체제] 교착 상태 (0) | 2021.12.17 |
---|---|
[운영체제] 동기화 도구들: Liveness (0) | 2021.12.17 |
[운영체제] 동기화 도구들: 세마포 (0) | 2021.12.17 |
[운영체제] 동기화 도구들: Mutex Locks (0) | 2021.12.16 |
[운영체제] 동기화 도구들: 동기화를 위한 하드웨어 지원 (0) | 2021.12.16 |