조건 변수를 활용하여 여러 쓰레드의 순서를 동기화 할 수 있었는데,
이는 뮤텍스와 같이 사용되어 조금은 복잡한 코드였다.
세마포어를 잘 활용하면 조건 동기화를 동시에 해결할 수 있다.
원래의 조건 동기화 코드는 조건 변수를 사용하기 전과 후에 상호 배제를 위해서 mutex를 사용했지만 세마포어는 그 자체로 상호 배제를 만족하므로
sem_t s;
void * child (void *args) {
printf(“child\n”);
sem_post(&s);
return NULL;
}
int main(int argc, char *argv[]) {
sem_init(&s, 0, 0);
printf(“parent: begin\n”);
pthread_t c;
pthread_create(c, NULL, child, NULL);
sem_wait(&s);
printf(“parent: end\n”);
return 0;
}
메인 쓰레드에서 semaphore의 wait, 자식 쓰레드에서 semaphore의 post로 자식 쓰레드가 끝날 때 까지 부모 쓰레드를 block시킬 수 있다.
semaphore는 count 변수(세마포어 변수)의 갯수를 늘렸다가 줄여가며 쓰레드가 임계 구역을 사용하는 갯수를 제한한다고 했었는데, 조건 동기화에서는 그 값을 0으로 초기화 해주어 wait가 처음 호출되는 곳에서 자연스럽게 세마포어 변수가 음수가 되어 그 쓰레드가 대기상태로 변하게 한다.
생산자 소비자 문제 - 세마포어
위의 두개 코드는 세마포어로 생산자 소비자 문제를 해결한 것이고,
밑의 두개 코드는 mutex와 pthread api의 wait, signal 함수로 해결한 것이다.
먼저 put, get을 수행하기 위한 버퍼를 소비자와 생산자가 공유하고 있으므로 sem_wait(&m)으로 상호 배제를 만족해준다.
생산자 코드 - 빈 슬롯(&emtpy)에 값이 남아 있다면 생산자가 쓰레드를 추가할 수 있다는 뜻이므로(put 호출) wait의 조건을 empty로 넣어주고, put이 끝나면 sem_post로 &fill로 인자를 주어 처리할 쓰레드가 있다면 처리하라는 뜻으로 소비자 큐에서 쓰레드를 깨워준다.
소비자 코드 - 만약 대기큐에 값이 존재한다면 쓰레드를 처리할 수 있다(get 호출) wait의 조건을 fill로 넣어주고 get이 끝나면 sem_post로 empty인자를 주어 생산할 쓰레드가 있다면 생산하라는 뜻으로 생산자 큐에서 쓰레드를 깨워준다.
하지만 소비자 코드에서 상호 배제를 수행후(lock) fill에 값이 없어 대기하게 된다면 unlock 하지 않는 이상 생산자에서 다시 접근하여 깨울 수가 없으므로 다음과 같은 순서로 바꿔주어야 한다.
이렇게 하면 put과 value에서 쓰레드를 추가하고 처리하는 과정에서 상호배제를 만족할 수 있고, empty와 fill을 이용하여 생산자 소비자 코드에서 각각 작업이 끝나면 서로를 호출하여 조건 동기화도 해결할 수 있다.
'CS > OS' 카테고리의 다른 글
Dining Philosophers Problem - 식사하는 철학자 문제 (0) | 2022.05.27 |
---|---|
Dead Lock - Resource-Allocation Graph (0) | 2022.05.27 |
condition Synchronization - 생산자 소비자 문제 (0) | 2022.05.25 |
Semaphore with 수도 코드 (0) | 2022.05.25 |
Race condition과 간단한 동기화 (0) | 2022.05.23 |