pthreads
조건부 변수
수색…
소개
조건부 변수는 스레드가 다른 스레드에서 발생하는 것을 기다리고 싶을 때 유용합니다. 예를 들어, 하나 이상의 생성 쓰레드와 하나의 소비 쓰레드를 가진 생산자 / 소비자 시나리오에서, 조건 변수는 새로운 쓰레드가 사용 가능한 쓰레드를 알리기 위해 사용될 수있다.
비고
일반 과정
조건부 변수 (생산자 / 소비자 예제의 queueCond)에 대한 대기는 항상 mutex (생산자 / 소비자 예제의 queueMutex)와 결합되며 항상 "정상적인"상태 변수 (queue.empty )를 생산자 / 소비자 예제에서 사용). 올바르게 사용하면 소비자에게 새로운 데이터가 누락되지 않습니다.
일반적으로 프로세스는 다음과 같아야합니다.
- 신호 스레드의 경우 :
- 뮤텍스 잠금
- 모든 데이터 및 상태 변수 업데이트
- 조건 변수 신호
- 뮤텍스 잠금 해제
- 대기중인 스레드의 경우 :
- 뮤텍스 잠금
- 상태 변수에
while루프를 수행하고 데이터가 준비되지 않은 한 반복합니다. -
while루프에서는pthread_cond_wait()조건 변수를 기다린다. -
while루프가 종료되면 새로운 데이터가 준비되어 있고 뮤텍스가 잠겨 있는지 확인합니다 - 데이터로 무언가를하십시오
- 뮤텍스의 잠금을 해제하고 반복하십시오.
시그널링과 대기 스레드가 언제 스케줄링 되든 관계없이이 스킴을 사용하면 대기중인 쓰레드는 결코 데이터를 놓칠 수 없다. (유효한 데이터가 준비되면 영원히 기다리지 않아도된다.) 이는 신호 스레드의 단계를 수동으로 실행하고 대기중인 스레드의 각 단계에 대해 뮤텍스, 상태 및 상태 변수의 상태를 기록하여 실현할 수 있습니다.
pthread_cond_wait 와 뮤텍스
위의 프로세스를 용이하게하려면 mutex가 잠긴 상태로 pthread_cond_wait() 를 호출해야합니다. 호출되면, pthread_cond_wait() 는 쓰레드를 잠자기 상태로 만들기 전에 뮤텍스의 잠금을 해제하고, 어떤 이유에서든 리턴하기 바로 전에 뮤텍스를 다시 잠급니다. 이것은 또한 다른 스레드가 현재 뮤텍스를 잠근 경우 pthread_cond_wait() 는 뮤텍스가 잠금 해제 될 때까지 대기하고 대기중인 스레드가 실제로 뮤텍스를 획득 할 때까지 잠글 것을 시도하는 다른 스레드와 함께 스레드와 경쟁 할 것이라는 것을 의미합니다. 동시에 뮤텍스.
허위 모닝콜
또한 상태 변수를 기다리는 while 루프가 간단한 if 문으로 대체 될 수있는 것처럼 보일 수 있습니다. 그러나 Posix 표준은 pthread_cond_wait() 가 실제로 신호를받지 않고 대기 중에 소위 "가짜"웨이크 업을 수행 할 수 있으므로 while 루프가 필요합니다. 따라서 코드는 pthread_cond_wait() 가 실제로 시그널링 되었기 때문에 반환되었는지 또는 이러한 허위 웨이크 업 중 하나 때문에 상태 변수를 다시 검사해야합니다.
생산자 / 소비자 예제
pthread_mutex_t queueMutex;
pthread_cond_t queueCond;
Queue queue;
void Initialize() {
//Initialize the mutex and the condition variable
pthread_mutex_init(&queueMutex, NULL);
pthread_cond_init(&queueCond, NULL);
}
void Producer() {
//First we get some new data
Data *newData = MakeNewData();
//Lock the queue mutex to make sure that adding data to the queue happens correctly
pthread_mutex_lock(&queueMutex);
//Push new data to the queue
queue.push(newData);
//Signal the condition variable that new data is available in the queue
pthread_cond_signal(&queueCond);
//Done, unlock the mutex
pthread_mutex_unlock(&queueMutex);
}
void Consumer() {
//Run the consumer loop
while(1) {
//Start by locking the queue mutex
pthread_mutex_lock(&queueMutex);
//As long as the queue is empty,
while(queue.empty()) {
// - wait for the condition variable to be signalled
//Note: This call unlocks the mutex when called and
//relocks it before returning!
pthread_cond_wait(&queueCond, &queueMutex);
}
//As we returned from the call, there must be new data in the queue - get it,
Data *newData = queue.front();
// - and remove it from the queue
queue.pop();
//Now unlock the mutex
pthread_mutex_unlock(&queueMutex);
// - and process the new data
ProcessData(newData);
}
}