이전 포스트에서 다루었던 프로세스 동기화 시 공유 데이터 관리
문제에서 상호 배제
를 충족하기 위한 방법이다.
뮤텍스 락 (Mutex Locks) : 가장 간단한 방법으로 임계 영역에 진입할 때 열쇠를 받고 나올 때 열쇠를 반납하는 개념으로 2개의 프로세스 간의 동기화를 제어 한다.
세마포어 (Semaphore) : 뮤텍스와 달리 n개의 프로세스 간의 동기화를 제어 할 수 있다.
모니터 (Monitor) : 뮤텍스와 세마포어의 단점을 해소한 방법으로 자바에서 사용된다.
열쇠를 사용하여 임계 영역에 진입한다. 그리고 임계 영역을 모두 수행한 후에는 열쇠를 반납한다.
따라서, 열쇠를 얻는 과정 (acquire lock)
과 열쇠를 반납하는 과정 (release lock)
이 필요하며, aquire와 relase 과정은 반드시 atomic 하게 수행되어야 한다.
즉, aquire함수나 relase 함수 내부에서 중단된 후 context switch 가 일어나면 안된다.
acquire(){
while(!available){
// 열쇠가 현재 사용중이므로
// 기다린다...(Busy waiting)
}
// 열쇠 획득 후 사용중이라고 표시해준다.
available = false;
}
release(){
avaiable=true;
}
acquire 함수
에서 어떤 프로세스가 임계 영역에 접근하기 위해서는 열쇠가 release 될 때 까지 무한 루프
해야하는 문제
위에서 Busy waiting을 일으키는 Mutex Lock을 SpinLock
이라고 말하며, 이 SpinLock의 구현방식은 멀티코어 환경에서 아래와 같이 동작한다.
그림에서 세번째 CPU의 프로세스이름을 프로세스 3 으로 했어야했는디,,
세마포어는 wait()
과 signal()
이라는 두 개의 Atomic한 함수로 구성된다.
여기서 S는 정수 변수이며 현재 공유 데이터로 접근 가능한 출입문의 갯수라고 생각하면 쉽다.
wait(S){
while(S<=0){
// 모든 출입문이 꽉 참
// Busy wait
}
S--;
}
signal(S){
S++;
}
S = 1
인경우로, 이는 뮤텍스 락과 비슷하게 동작한다.
S = n ( n > 1 )
인 경우로 S가 무한대로 증가할 수 있다. 이는, 여러개의 인스턴스를 가진 자원에 사용될 수 있다. ex) 컴퓨터에 등록된 프린터가 3개인 경우, 인스턴스(프린터 )는 3개이다.
S를 사용 가능한 자원의 갯수로 초기화 시켜준다.
프로세스가 자원을 사용할 경우
wait()
을 실행하여 현재 사용가능한 S의 갯수를 줄여준다.프로세스가 자원을 반납할 경우
signal()
을 실행하여 현재 사용가능한 S의 갯수를 늘려준다.S = 0 인 경우 (= 모든 리소스가 사용 중인 경우)
Busy wait
Statement1을 가진 프로세스A와 Statement2를 가진 프로세스 B가 동시에 실행 될 경우, Statement1이 무조건 Statement2 보다 먼저 실행되어야 한다고 했을 때 어떻게 순서를 지킬 수 있을까?
이를 위해서는 프로세스A가 종료된 후, 프로세스 B가 실행된다는 것을 보장해야한다.
따라서 프로세스 A와 프로세스 B가 세마포어 Synch
를 공유하고, wait 함수
에서 무조건 세마포어 synch를 0으로 초기화 해준다.
// 프로세스 A
Statement1; // 생략
signal(synch); // synch 증가
// 프로세스 B
wait(synch); // synch를 0으로 초기화한다.
Statement2;
뮤텍스 락과 마찬가지로 Busy waiting 문제가 있다. 세마포어 방법에서는 여러개의 자원
을 사용하므로 아래와 같이 wait함수와 signal 함수를 수정하여 문제를 해결 할 수 있다.
wait() 함수에서 세마포어가 음수라면 해당 프로세스 sleep 시켜 waiting queue
에 적재한다.
signal() 함수에서 waiting queue에서 대기 중인 프로세스 wake-up 하여 ready queue
에 적재한다.