이경우에는 세마포어의 초기값을 0으로 해야한다. 부모 쓰레드가 자식 쓰레드를 생성하고 자식 쓰레드가 아직 실행하지 않을 경우에도 부모 쓰레드는 대기해야한다.
그렇기 때문에 0으로 초기화하면 부모 쓰레드는 wait을 만나자마자 -1로 인해 대기된다. 이후 자식이 실행되면 세마포어의 값을 0으로 올려주고 부모가 실행할 수 있는 조건이 만족된다.
1.4 생산지/소비자(유판 버퍼) 문제
세마포어로 생산자/소비자를 구현하기 위해선 세가지 기법이 필요하다.
full, empty 조건 추가(두개의 세마포어 값을 사용한다.)
상호 배제 추가하기
교착 상태 방지
full, empty 조건 추가
생산자는 소비자의 세마포어에만 영향을 주어야하고, 반대로 소비자는 생산자의 세마포어에만 영향을 주어야한다.
그렇기 때문에 생산자는 empty를 wait하고 full을 post한다.
소비자는 full을 wait하고 empty를 post한다.
생산자는 empty 락을 획득해야지 값들을 버퍼에 추가할 수 있으며, 버퍼가 다차면 소비자에게 락을 전달해 버퍼에 값을 소비하라고 요청해야한다.
소비자는 full 락을 획득해야지 버퍼에 있는 값들을 소비할 수 있으며, 버퍼가 비게 되면 생산자에게 락을 전달해 버퍼에 값을 넣어달라고 요청해야한다.
상호 배제의 추가
두 개의 생산자 pa, pb가 동시에 put()을 호출하게 되면 pa가 버퍼에 값을 넣고 fill 카운터 변수를 1로 증가시키기 전에 인터럽트가 발생하고 pb가 이어서 같은 버퍼 공간에 값을 덮어 쓰게 된다.
생산자와 소비자 쓰레드 중 소비자가 먼저 실행되었다. mutex를 획득 후 full 변수에 대하여 sem_wait()을 호출한다. 버퍼가 비어있다. 소비자는 대기모드로 전환된다. CPU를 양보하게 되는데
여기서 중요한 것은 소비자가 아직 mutex 락을 보유하고 있기 때문에 생산자는 실행할 수 없다.
정답: “과도하게 많은” 에 임계값을 정하고, 세마포어를 사용하여 문제가 되는 코드를 동시에 실행하는 쓰레드 개수를 제한한다.
우리는 이 접근법을 제어(throttling)라고 부르며 수락 제어의 한 형태로 간주한다.
1.8 세마포어 구현
저수준 동기화 기법인 락과 컨디션 변수를 사용하여 우리만의 세마포어를 만들어 본다.
voidstruct__Zem_t{intvalue;ptrhead_cond_tcond;pthread_mutex_tlock;}Zem_t;// 오직 하나의 쓰레드만 이 문장을 호출할 수 있음voidZem_init(Zem_t*s,intvalue){s->value=value;cond_init(&s->cond);Mutexinit(&s->lock);}voidZem_wait(Zem_t*s){Mutex_lock(&s->lock);while(s->value<=0)Cond_wait(&s->cond,&s->lock);s->value--;Mutex_unlock(&s->lock);}voidZem_post(Zem_t*s){Mutex_lock(&s->lock);s->value++;Cond_signal(&s->cond);Mutex_unlock(&s->lock);}
댓글남기기