모니터를 사용하는 이유
- 세마포 또는 mutex 락을 이용하여 임계구역 문제를 해결할 때 문제점
→ 프로그래머가 세마포를 잘못 사용할 시, 다양한 유형의 오류가 쉽게 발생할 수 있음 - 이러한 오류 처리를 위해 모니터 사용
- 전략 : 간단한 동기화 도구를 통합하여 고급 언어 구조물로 제공하는 것 → 모니터
- 모니터는 근본적인 고급 언어 구조물 중 하나
- Java, C# 등의 많은 프로그래밍 언어들이 모니터의 개념을 편입시킴
모니터 사용법(Usage)
ADT와 모니터
ADT(추상화된 데이터 형)
: 데이터와 해당 데이터를 조작하는 함수들의 집합을 하나의 단위로 묶어 보호- 이때 함수의 구현은 ADT의 특정한 구현과는 독립적
- 이때 함수의 구현은 ADT의 특정한 구현과는 독립적
모니터 형
: 모니터 내부에 프로그래머가 정의한 일련의 연산자 집합을 포함하는 ADT- 이때 모니터 내부에서 상호배제가 보장되어야 한다.
- 변수들의 선언을 포함하고, 이 변수들의 값은 그 형에 해당하는 한 인스턴스의 상태를 정의
- 모니터형은 해당 변수를 조작할 수 있는 프로시저/함수 본체도 같이 포함
모니터 코드 구문과 개략도
mointor monitor name
{
/* 공유 변수 선언 */
function P1(...){
...
}
function P2(...){
...
}
.
.
.
function Pn(...){
...
}
initialization_code(...){
...
}
}
- 모니터 형의 표현은 다른 프로세스들이 직접 사용할 수 없다.
→ 오직 모니터 내에 정의된 함수만 모니터 내에 지역변수와 형식 매개변수들에게 접근 가능- 모니터 구조물은 모니터 안에 항상 하나의 프로세스만이 활성화되도록 보장
→ 프로그래머들은 동기화 제약 조건을 명시적으로 코딩할 필요가 없다.
- 모니터 구조물은 모니터 안에 항상 하나의 프로세스만이 활성화되도록 보장
모니터 구조물 동기화 기법 정의
- 위에서의 모니터 구조물은 어떤 동기화 기법을 모델링하는데 충분하지 않다.
→ 이를 위해 부가적인 동기화 기법 정의가 필요 - 동기화 기법들은 condition이라는 구조물로 제공
- 프로그래머는 동기화 기법 작성이 필요할 때, 하나 이상의 condition형 변수를 정의할 수 있다.
- ex ) condition x, y;
- ex ) condition x, y;
- condition형 변수에 호출될 연산은
wait()
와signal()
밖에 없다.x.wait()
를 호출한 프로세스는 다른 프로세스가 x.signal()을 호출할 때까지 일시중지x.signal()
: 정확히 하나의 일시 중지 프로세스를 재개- 일시 중지된 프로세스가 없다면, 해당 연산은 아무런 효과 없음
→ x의 상태는 연산이 전혀 실행되지 않는 것과 같음- cf ) 세마포의
signal()
연산은 항상 세마포의 상태에 영향을 준다.
- cf ) 세마포의
- 일시 중지된 프로세스가 없다면, 해당 연산은 아무런 효과 없음
- 프로그래머는 동기화 기법 작성이 필요할 때, 하나 이상의 condition형 변수를 정의할 수 있다.
모니터에서 두 프로세스의 동시성
- 가정
x.signal()
연산이 프로세스 P에 의해 호출될 때,
조건 x와 연관된 일시 중지된 프로세스 Q가 있다고 가정
- 일시 중지된 스레드 Q가 실행을 재개하면, signal을 보낸 스레드 P는 반드시 대기해야 함
← 두 프로세스가 동시에 활성화되는 것을 막기 위해 - 두 프로세스는 개념적으로 실행을 멈추지 않고 계속할 수 있다. → 2가지 가능성 존재
Signal and wait
: P는 Q가 모니터를 떠날 때까지 대기 혹은 다른 조건을 기다림Signal and continue
: Q는 P가 모니터를 떠날 때까지 대기 혹은 다른 조건을 기다림- 문제점 : P가 계속 실행되고 Q가 기다린다면, Q가 원하는 논리적 조건이 참이 아닐 수 있게 됨
- 문제점 : P가 계속 실행되고 Q가 기다린다면, Q가 원하는 논리적 조건이 참이 아닐 수 있게 됨
- 두 가지 방법의 절충안 존재
- 스레드 P가
signal()
연산을 실행하면, 즉시 모니터를 떠나고 Q가 재개됨
- 스레드 P가
세마포를 이용한 모니터의 구현
- 각 모니터마다 mutex라는 이진 세마포가 정의되고 초기값은 1
- 프로세스는 모니터에 들어가기 전
wait(mutex)
를 실행 - 프로세스는 모니터를 나온 후에
signal(mutex)
를 실행
- 프로세스는 모니터에 들어가기 전
- 모니터 구현 시 signal-and-wait기법을 사용
- Signaling 프로세스는 next라는 이진 세마포가 추가로 필요함
- 이때, next 이진 세마포는 0으로 초기화된다.
← 실행 재개되는 프로세스가 모니터를 떠나든지,
wait() 할 때까지 자신이 다시 기다려야 하기 때문
- 이때, next 이진 세마포는 0으로 초기화된다.
- Signaling 프로세스는 자신을 중단시키기 위해 next를 사용할 수 있다.
- 정수형 변수 next_count는 next에서 일시 중지 되는 프로세스의 개수를 세기 위해 제공
- Signaling 프로세스는 next라는 이진 세마포가 추가로 필요함
모니터 안에서 상호 배제를 보장하는 코드 구현
wait(mutex);
...
body of F
...
if(next_count > 0) // 일시 중지 중인 프로세스가 있다면
signal(next); // 그 프로세스를 깨움
else // 일시 중지 중인 프로세스가 없다면
signal(mutex); // 모니터에서 나옴
조건 변수를 세마포로 구현하는 방법
- 각 조건 x마다 이진 세마포
x_sem
와 정수형 변수x_count
를 도입- 둘 다 초기값을 0으로 초기화한다.
x.wait() 구현
x_count++;
if(next_count > 0)
signal(next);
else
signal(mutex);
wait(x_sem);
x_count--;
x.signal() 구현
if(x_count > 0){
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
모니터 내에서 프로세스 수행 재개
모니터 안에서 프로세스가 수행 재개되는 순서
- 가정
- 조건 변수 x에 여러 프로세스가 일시 중지되어 있는 상태
- 어떤 프로세스가
x.signal()
연산을 수행하면, 일시 중지된 프로세스들 중 어느 것이 재개될까?
- 일시 중지된 프로세스를 선택하는 방법
FCFS(선입 선출) 방법
: 가장 오래 기다렸던 프로세스가 가장 먼저 깨어남
→ But, 많은 경우 이렇게 간단한 스케줄링 기법은 충분치 않음conditional-wait 구조물 사용
← FCFS 방법의 단점을 보완
Conditional-wait 구조물 사용
x.wait(c)
의 형태를 가짐- c : 정수 수식으로,
wait()
연산이 호출될 때 값이 계산됨- c의 값은 우선순위 번호(priority number)라고 불림
- 해당 값은 일시 중지되는 프로세스의 이름과 함께 저장
- 해당 값은 일시 중지되는 프로세스의 이름과 함께 저장
- c의 값은 우선순위 번호(priority number)라고 불림
- c : 정수 수식으로,
x.signal()
이 수행되면 가장 작은 우선순위 번호를 가진 프로세스가 다음번에 수행 재개- 이 기법이 사용되는 예시 → ResourceAllocator 모니터
ResourceAllocator 모니터
: 한 개의 자원을 여러 프로세스 사이에 할당해 주는 역할을 함- 프로세스가 자원을 할당받기를 원할 때 따라야 하는 순서
- R은 ResourceAllocator형의 인스턴스를 뜻함
- R은 ResourceAllocator형의 인스턴스를 뜻함
- 1. 각 프로세스가 할당받기 원하는 자원의 최대시간을 정한다.
2. 모니터는 이 중 가장 적은 시간을 희망한 프로세스에 자원을 할당
R.acquire(t); // 할당받기를 원하는 자원을 사용할 최대 시간(t)를 설정
...
access the resource;
...
R.release();
- 하나의 자원을 할당해 주는 모니터 코드 구현
monitor ResourceAllocator
{
boolean busy;
condition x;
void acquire(int time){
if(busy) x.wait(time);
busy = true;
}
void release(){
busy = false;
x.signal();
}
initialization_code(){
busy = false;
}
}
모니터 사용 시 발생할 수 있는 문제
- 하지만, 모니터의 개념은 예시한 순서가 그대로 지켜지는 것을 보장하지 않는다.
- 다음과 같은 상황에 문제가 발생할 수 있음
- 프로세스가 자원에 대한 허락을 받지 않고 자원을 액세스 할 경우
- 프로세스가 자원에 대한 허락을 받은 다음 그 자원을 방출하지 않을 경우
- 프로세스가 자원에 대한 허락을 받지 않았는데도, 그 자원을 방출할 경우
- 프로세스가 자원에 대한 허락을 받고, 방출하지 않은 상태에서 또 그 자원을 요청할 경우
모니터 문제 해결 방법
- 컴파일러 자체는 도움을 줄 수 없다.
- 자원 액세스 연산 자체를 ResourceAllocator 모니터 내부에 두는 방법
- 해당 방식을 사용하면, 스케줄링을 모니터 자체의 스케줄러에게 맡기는 것
→ 프로그래머가 코딩한 스케줄링 방식을 사용하는 것이 아님 - 프로세스들의 올바른 순서 보장을 위해서 검사해야 할 것
- ResourceAllocator 모니터 자체
- ResourecAllocator 모니터가 관리하는 자원 사용하는 모든 프로그램
- 해당 방식을 사용하면, 스케줄링을 모니터 자체의 스케줄러에게 맡기는 것
- 시스템 정상 동작을 알기 위해 2가지 조건을 검사해야 함
- 프로세스들이 모니터를 정확한 순서에 맞추어 호출하는지 검사
- 비협조적인 프로세스가 모니터 공유 자원을 직접 액세스 하지 않는다는 것을 보장받아야 함.
- 비협조적 프로세스는 액세스 제어 프로토콜을 사용하지 않음
→ 모니터가 정한 상호 배제 규칙 경로를 무시할 수도 있음
→ 위 2가지 조건을 만족 시, 시간 종속적 오류가 일어나지 않고, 원하는 스케줄링이 지켜짐
- 비협조적 프로세스는 액세스 제어 프로토콜을 사용하지 않음
- 이 해결 방식의 한계점
- 규모가 큰 프로그램 또는 동적인 시스템에서는 비합리적
- 작은 규모며 정적인 시스템에서는 가능함