0) 개념
- 세마포 S는 정수 변수로서, 초기화를 제외하고는 단지 두 개의 표준 원자적 연산 wait()과 signal()로만 접근할 수 있다.
- wait()과 siganl() 이 두 연산은 원자적으로 수행되어야한다.
wait(S){
while(S <= 0)
; //busy wait -> 검사하는 과정을 뜻한다.
S--;
}
siganl(S){
S++
}
1) 세마포 사용법
-
카운팅 세마포 : 제한이 없는 영역의 값을 갖는다.
- 유한한 개수를 가진 자원에 대한 접근을 제어하는데 사용가능
// S1에서 생성하여 S2에서 소바하는 카운팅 세마포를 구현한 것
S1;
signal(synch);
wait(synch);
S2;
-
이진 세마포 : 0과 1사이의 값만 가능하다. → Mutex 락과 유사하게 동작한다.
2) 세마포 사용법
- 기존에 acquire lock과 relaeas lock을 통하여 lock을 받고 반납하며 스핀락 방식으로 했던 mutex의 문제점을 살짝 개선하여 세마포 같은 경우에는 만약 대기해야하는 상황의 경우 프로세스를 일시 중지 상태로 바꿔 대기 queue에 넣었다가 자원이 생성되면 FIFO 방식으로 다시 수행하는 방식
- 각 세마포는 정수 값과 프로세스 제어 블록의 리스트에 대한 포인터를 갖고 있다.
- 한정된 대기를 보장하도록 리스트에 프로세스를 추가하고 삭제하는 한 가지 방법은 FIFO 큐를 사용하는 것으로 세마포가 큐의 머리와 꼬리에 대한 포인터를 모두 가지게 된다.
- 원자적으로 두 wait()와 signal()이 실행돼야 하기에 SMP 시스템은 CAS 또는 스핀 락 같은 방식같은 다른 기법을 제공해야한다.
- sleep() 함수가 바로 일시 중지시키는 함수이다.
- 이 때 대기 큐에서 깨우는 함수가 바로 wakeup() 함수이다.
typedef struct{
int value;
struct process *list; /* 프로세스 제어 블록의 리스트에 대한 포인터 */
} semaphore;
wait(semaphore *S) {
S -> value--;
if (S->value <0) {
add this process to S->list;
sleep();
}
}
signal(semaphore *S){
S->value++;
if (S->value <=0) {
remove a process P from S-> list;
wakeup(P);
}
}