synchronization[semapo]
semapo
뮤텍스 락은 하나의 공유 자원에 접근하는 프로세스를 상정한 방식입니다.
하지만 세마포는 뮤텍스 락과는 비슷하나, 다른 점이 있다면 여러개의 공유 자원이 있다는 점 입니다.
뮤텍스 락은 자물쇠를 걸어 잠금으로써 접근을 제한했다면, 세마포는 차단기처럼 가도 되는지, 가면 안되는지로 접근을 제한합니다.
세마포는 뮤텍스락과 비슷하게 하나의 전역 변수, 두 개의 함수로 단순하게 구현할 수 있습니다.
- 전역 변수 S : 임계 구역에 진입할 수 있는 프로세스의 개수 입니다.
- wait 함수 : 진입이 가능한지 여부를 알려주는 함수입니다.
- signal 함수 : 기다리고 있는 프로세스에게 진입이 가능하다는 신호를 주는 함수입니다.
예시코드
1
2
3
wait();
// 임계 구역내의 활동
signal();
1
2
3
4
5
6
7
8
wait() {
while ( S <= 0 );
S--;
}
signal () {
S++;
}
wait()
만일 임계 구역에 진입할 수 있는 프로세스 개수가 0개 이하라면 사용할 수 있는 자원이 있는지 반복적으로 확인하고,
signal()
임계 구역에 진입할 수 있는 프로세스 개수가 하나 이상이면 S를 1감소 시키고 임계 구역에 진입합니다.
예를 들어서 P1,P2,P3가 두개의 공유자원에 접근한다고 가정을 해보겠습니다.
- P1이 wait를 호출 합니다. ( S = 2 → S = 1 )
- P2이 wait를 호출 합니다. ( S = 1 → S = 0 )
- P3가 wait를 호출 하였으나, S = 0 이기에 무한 한복하며 S를 확인합니다.
- P1이 임계 구역 작업을 종료하고, signal을 호출합니다 ( S = 0 → S = 1 )
- P3가 S가 1이 됨을 확인하고, 임계 구역에 진입 합니다. ( S = 1 → S = 0 )
하지만 여기서 뮤텍스 락과 같이 세마포의 문제점은, 프로세스가 무한히 대기중일 때, 반복적으로 S를 확인한다는 점 입니다. ( busy wait → Spin lock)
이 말은 즉, 프로세스가 바쁜 대기를 반복한다는 점 입니다. 이로 인해 프로세스는 더 생산성 있는 작업을 할 수 있는데 CPU주기를 낭비한다는 점에서 손해입니다.
그래서 세마포는 이를 해결하기 위해 더 좋은 방법을 사용합니다.
코드 먼저 살펴보겠습니다.
1
2
3
4
5
6
7
wait() {
S--;
if ( S < 0 ) {
// 프로세스를 대기 큐에 삽입합니다.
block()
}
}
1
2
3
4
5
6
7
signal() {
S++;
if ( S <= 0 ){
// 프로세스를 대기 상태에서 준비 상태로 바꿉니다.
wakeup(p);
}
}
wait()
먼저 임계 구역에 진입할 수 있는 프로세스의 개수가 0개면 들어올려고 하는 프로세스를 대기 큐에 삽입합니다.
signal()
임계 구역에 진입할 수 있는 프로세스의 개수가 0개에서 1개로 늘어나면, 대기 큐에있던 프로세스를 대기 상태에서 준비 상태로 바꿉니다.
예시를 살펴보겠습니다.
- P1이 wait를 호출 합니다. ( S = 2 → S = 1 )
- P2이 wait를 호출 합니다. ( S = 1 → S = 0 )
- P3가 wait를 호출하였으나, S = -1 ( 1감소 ) 으로 바뀌었으므로, P3는 PCB의 대기 큐에 삽입하고 대기 상태로 전환합니다.
- P1이 임계 구역 작업을 종료하고, signal을 호출합니다. ( S = -1 → S = 0 ), 이때 S가 -1에서 0이 되었으므로, 대기 큐에 있던 P3를 대기큐에서 꺼내온 후, 준비 큐로 옮기면서 대기 상태에서 준비 상태로 전환합니다.
- 준비 상태로 바뀐 P3는 임계 구역에 진입합니다.
그리고 세마포를 이용하여 프로세스의 실행 순서도 원하는 대로 바꿀 수 있습니다.
사용 방법은 실행할 프로세스 뒤에 signal 함수, 그 다음에 실행할 프로세스 앞에 wait함수를 붙이면 됩니다.