Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>
Docbook 원문

pthread_cond_wait(3)

1장. pthread_cond_wait(3)

조건변수 관련 연산


1.1. 사용법

#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
int pthread_cond_destroy(pthread_cond_t *cond);
		


1.2. 설명

조건변수는 쓰레드간 동기화를 위해서 사용하는 장치로써, 공유되는 데이터의 안정을 보장하기 위한 용도로 주로 사용된다. 조건변수의 기본적인 작동방식은 다음과 같다. 하나의 쓰레드는 조건변수에 시그널이 전달될 때까지 특정영역에서 대기 상태에 놓이게 된다. 만약 다른 쓰레드가 조건변수에 시그널을 보낸다면 대기 상태에서 풀리고 다음 코드로 넘어가게 된다.

조견변수는 race condition을 피해야하므로 반드시 뮤텍스(mutex)와 함께 사용되어야 한다.

pthread_cond_init()는 조건벼수 cond를 초기화하기 위해서 사용되며, cond_attr를 이용해서 조건변수의 특성을 결정할 수 있다. NULL을 사용하면 기본특성이 사용된다. 리눅스의 경우 cond_attr은 무시된다.

pthread_cond_t는 상수 PTHREAD_COND_INITIALIZER을 이용해서 static하게 초기화 시킬 수 있다.

pthread_cond_signal()은 조건변수cond에 시그널을 보내어서 다른 (조건변수 cond에서 기다리는)쓰레드를 깨운다. 만약 cond에서 기다리는 쓰레드가 없다면 아무런 일도 일어나지 않게 된다. 만약 여러개의 쓰레드가 cond에서 기다리고 있다면 정확히 이중 하나가 깨어나게 된다. 그러나 어떤게 깨어날지는 알 수 없다.

pthread_cond_broadcast()는 조건변수cond에서 기다리는 모든 쓰레드를 깨운다. 기다리는 쓰레드가 없다면 아무런 일도 일어나지 않는다.

pthread_cond_wait()는 조건변수 cond로 시그널이 전달되기를 기다린다. 이 함수는 호출되면 자동적으로 mutex잠금을 되돌려준다 - 내부적으로 pthread_unlock_mutex()를 호출한다. -. 이 함수를 호출한 쓰레드는 조건변수에 시그널이 전달될 때까지 기다리며, 이때 CPU는 소비하지 않는다. 시그널을 전달받아서 쓰레드가 깨어나면 자동적으로 mutex잠금을 얻는다 - pthread_lock_mutex()를 사용-.

pthread_cond_timedwait()는 pthread_cond_wait()의 시간제한 버젼으로 abstime를 이용해서 제한시간이 지날 때까지 시그널이 전달되지 않았을경우 리턴된다는 것을 제외하고는 pthread_cond_wait()와 동일하게 작동한다. 제한시간이 지나서 리턴되었을 경우 errno로 ETIMEOUT을 설정한다. abstime에 대해서는 time(2)와, gettimeofday(2)를 참고하기 바란다.

pthread_cond_destroy()는 조건변수를 삭제해서 자원을 되돌려준다.


1.3. 취소(CANCELLATITON)

pthread_cond_wait()와 pthread_cond_timedwait()는 취소상태함수 이다. 이에 대한 자세한 내용은 Thread 취소와 종료를 참고하기 바란다.


1.4. 반환값

성공할경우 0을 실패했을경우에는 -1을 반환하며, 적당한 errno 값을 설정한다.


1.5. 에러

pthread_cond_init(), pthread_cond_signal(), pthread_cond_broadcast(), pthread_cond_wait()는 에러코드를 리턴하지 않는다.

pthread_cond_timewait()의 경우 다음과 같은 에러코드를 리턴한다.

ETIMEDOUT

시간초과 검사를 위해 지정된 abstime를 초과해서 시그널이 발생하지 않았을 때.

EINTR

(유닉스 POSIX)시그널등에 의해서 인터럽트가 발생했을 때

pthread_cond_destory()함수는 다음과 같은 에러코드를 리턴한다.

EBUSY

cond에 기다리고 있는 쓰레드가 남아있다.


1.6. 예제

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>

using namespace std;

void *ping(void *);
void *pong(void *);

pthread_mutex_t sync_mutex;
pthread_cond_t  sync_cond;

pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  gcond  = PTHREAD_COND_INITIALIZER;
                                                   
int main()
{
    vector<void *(*)(void *)> thread_list;
    vector<pthread_t> tident(10);
    int thresult;
    int status;
    int i;
                                          
    pthread_mutex_init(&sync_mutex, NULL);
    pthread_cond_init(&sync_cond, NULL);

    thread_list.push_back(pong);
    thread_list.push_back(ping);

    for(i = 0; i < thread_list.size(); i++ )
    {
        pthread_mutex_lock(&sync_mutex);
        if (pthread_create(&tident[i], NULL, thread_list[i], (void *)NULL) <0)
        {
            perror("error:");
            exit(0);
        }
        pthread_cond_wait(&sync_cond, &sync_mutex);
        pthread_mutex_unlock(&sync_mutex);
    }
    for (i = 0; i < tident.size(); i++)
    {
        pthread_join(tident[i], (void **)&status);
    }
}
                         
void *ping(void *data)
{
    int i=0;
    pthread_mutex_lock(&sync_mutex);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
    while(1)
    {
        pthread_mutex_lock(&gmutex);
        printf("%d : ping\n", i);
        pthread_cond_signal(&gcond);
        pthread_cond_wait(&gcond, &gmutex);
        pthread_mutex_unlock(&gmutex);
        usleep(random()%100);
        i++;
    }
}
                                                   
void *pong(void *data)
{
    int i = 0;
    pthread_mutex_lock(&sync_mutex);
    sleep(1);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
    while(1)                              
    {
        pthread_mutex_lock(&gmutex);
        pthread_cond_wait(&gcond, &gmutex);
        printf("%d : pong\n", i);
        pthread_cond_signal(&gcond);
        pthread_mutex_unlock(&gmutex);
        i++;
    }
}
		
위의 예제는 ping&pong 프로그램으로 ping 쓰레드와 pong쓰레드가 번갈아 가면서 "ping", "pong"를 날리는 프로그램이다. 쓰레드 동기화를 위해서 pthread_cond_wait()관련 함수들이 사용되고 있다.