/* Store an integer in the buffer */
static void
put (struct prodcons *b, int data)
{
pthread_mutex_lock (&b->lock);
/* Wait until buffer is not full */
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait (&b->notfull, &b->lock);
/* pthread_cond_wait reacquired b->lock before returning */
}
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE)
b->writepos = 0;
/* Signal that the buffer is now not empty */
pthread_cond_signal (&b->notempty);
pthread_mutex_unlock (&b->lock);
}
보시면..
pthread_cond_wait (&b->notfull, &b->lock);
pthread_cond_wait의 인자로..두가지를 넘기는데
첫번째는 컨디션 변수이고 하나는 뮤텍스 락입니다.
왜 pthread_cond_wait를 하는데 이 녀석과 관계가 있는 뮤텍스를
넘겨 주는 것일까요?
그것은, 특정한 신호를 기다릴때.. 자신이 얻은 뮤텍스 락을
풀어주고 잠들기 때문입니다.(잠금을 풀어 주지 않으면, 다른 쓰레드가
뮤텍스 영역에 들어 갈수 없어서 특정한 신호를 줄수 없겠죠//)
그리고 나서 신호를 받으면 다시 잠금을 얻은 다음... 뒤에
루틴을 수행하겠지요..
자 이제 질문에 답은 나왔습니다.
시그널은 그냥 이제 곧 잠금이 풀릴 것이란 신호에 불과한
것이고.. 결국은 다시 잠금을 얻을 수 있도록 다른 쓰레드에서 뮤텍스락을
풀어 주어야 겠지요..
아래의 pthread구현 소스를 보시면
명확하게 아실수 있을 껍니다.
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
pthread_extricate_if extr;
int already_canceled = 0;
int spurious_wakeup_count;
/* Check whether the mutex is locked and owned by this thread. */
if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
&& mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
&& mutex->__m_owner != self)
return EINVAL;
/* Set up extrication interface */
extr.pu_object = cond;
extr.pu_extricate_func = cond_extricate_func;
/* Atomically enqueue thread for waiting, but only if it is not
canceled. If the thread is canceled, then it will fall through the
suspend call below, and then call pthread_exit without
having to worry about whether it is still on the condition variable queue.
This depends on pthread_cancel setting p_canceled before calling the
extricate function. */
직접 테스트해 보세요. (냉무)
.
Re: 스레드 질문입니다. pthread , condtion 과 signal
다음은 간단한 thread 프로그램의 일부입니다..
/* Store an integer in the buffer */
static void
put (struct prodcons *b, int data)
{
pthread_mutex_lock (&b->lock);
/* Wait until buffer is not full */
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait (&b->notfull, &b->lock);
/* pthread_cond_wait reacquired b->lock before returning */
}
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE)
b->writepos = 0;
/* Signal that the buffer is now not empty */
pthread_cond_signal (&b->notempty);
pthread_mutex_unlock (&b->lock);
}
보시면..
pthread_cond_wait (&b->notfull, &b->lock);
pthread_cond_wait의 인자로..두가지를 넘기는데
첫번째는 컨디션 변수이고 하나는 뮤텍스 락입니다.
왜 pthread_cond_wait를 하는데 이 녀석과 관계가 있는 뮤텍스를
넘겨 주는 것일까요?
그것은, 특정한 신호를 기다릴때.. 자신이 얻은 뮤텍스 락을
풀어주고 잠들기 때문입니다.(잠금을 풀어 주지 않으면, 다른 쓰레드가
뮤텍스 영역에 들어 갈수 없어서 특정한 신호를 줄수 없겠죠//)
그리고 나서 신호를 받으면 다시 잠금을 얻은 다음... 뒤에
루틴을 수행하겠지요..
자 이제 질문에 답은 나왔습니다.
시그널은 그냥 이제 곧 잠금이 풀릴 것이란 신호에 불과한
것이고.. 결국은 다시 잠금을 얻을 수 있도록 다른 쓰레드에서 뮤텍스락을
풀어 주어야 겠지요..
아래의 pthread구현 소스를 보시면
명확하게 아실수 있을 껍니다.
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
volatile pthread_descr self = thread_self();
pthread_extricate_if extr;
int already_canceled = 0;
int spurious_wakeup_count;
/* Check whether the mutex is locked and owned by this thread. */
if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
&& mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
&& mutex->__m_owner != self)
return EINVAL;
/* Set up extrication interface */
extr.pu_object = cond;
extr.pu_extricate_func = cond_extricate_func;
/* Register extrication interface */
THREAD_SETMEM(self, p_condvar_avail, 0);
__pthread_set_own_extricate_if(self, &extr);
/* Atomically enqueue thread for waiting, but only if it is not
canceled. If the thread is canceled, then it will fall through the
suspend call below, and then call pthread_exit without
having to worry about whether it is still on the condition variable queue.
This depends on pthread_cancel setting p_canceled before calling the
extricate function. */
__pthread_lock(&cond->__c_lock, self);
if (!(THREAD_GETMEM(self, p_canceled)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
enqueue(&cond->__c_waiting, self);
else
already_canceled = 1;
__pthread_unlock(&cond->__c_lock);
if (already_canceled) {
__pthread_set_own_extricate_if(self, 0);
pthread_exit(PTHREAD_CANCELED);
}
pthread_mutex_unlock(mutex);
spurious_wakeup_count = 0;
while (1)
{
suspend(self);
if (THREAD_GETMEM(self, p_condvar_avail) == 0
&& (THREAD_GETMEM(self, p_woken_by_cancel) == 0
|| THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
{
/* Count resumes that don't belong to us. */
spurious_wakeup_count++;
continue;
}
break;
}
__pthread_set_own_extricate_if(self, 0);
/* Check for cancellation again, to provide correct cancellation
point behavior */
if (THREAD_GETMEM(self, p_woken_by_cancel)
&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
THREAD_SETMEM(self, p_woken_by_cancel, 0);
pthread_mutex_lock(mutex);
pthread_exit(PTHREAD_CANCELED);
}
/* Put back any resumes we caught that don't belong to us. */
while (spurious_wakeup_count--)
restart(self);
pthread_mutex_lock(mutex);
return 0;
}
댓글 달기