[C/C++]thread 조건변수 다루기 - pthread_cond_broadcast()

프로그래밍 팁 2015. 9. 1. 01:34

 멀티코어를 기반으로 한 프로그래밍을 수행할 때 가장 중요한 요소라면 여러 개의 thread를 통제할 수 있는 방법에 대한 정확한 이해라고 생각합니다. 다수의 thread가 하나의 변수를 동시에 접근하려 하는 것을 통제하기 위해 주로 mutex와 semaphore가 사용됩니다.

 이번 포스팅에서는 C/C++ 언어를 기반으로 thread를 좀 더 섬세하게 다룰 수 있는 조건변수(Condition Variable)에 대해 살펴보도록 합니다.


 조건변수를 사용하게 되면 기존의 mutex로 통제하는 방식에서 좀 더 발전한 방식을 사용합니다. 이에 사용되는 thread 함수들을 간단하게 살펴보겠습니다.


int pthread_cond_wait( pthread_cond_t* cond, pthread_mutex_t* mutex );

 동작중인 thread를 잠시 중단시킵니다 condition과 mutex인자를 모두 적용합니다. 다른 thread로부터 signal이나 broadcast를 받았을 경우 해당 함수는 아래의 함수와 같은 동작을 하게 됩니다.

int pthread_mutex_lock(pthread_mutex_t *mutex);


int pthread_cond_signal(pthread_cond_t *cond);

 cond 인자를 가지고 pthread_cond_wait() 함수를 실행중인 하나의 thread를 깨웁니다. 만약 cond 인자를 잡고있는 thread가 다수일 경우 단 하나의 thread만 깨어납니다.


int pthread_cond_broadcast(pthread_cond_t *cond);

 cond 인자를 가지고 pthread_cond_wait() 함수를 실행중인 모든 thread를 깨웁니다. 만약 cond 인자를 잡고 있는 thread가 다수일 경우 mutex를 먼저 잡은 thread가 먼저 동작되며 나머지 thread는 mutex를 받을 때 까지 대기상태를 유지합니다.


int pthread_mutex_unlock(pthread_mutex_t *mutex);

 pthread_cond_signal()함수 혹은 pthread_cond_broadcast() 함수에 의해 깨어난 thread가 실행을 끝내고 종료하기 전에 자신이 가지고 있는 mutex를 풀어줍니다. 만약 해당 thread가 이를 실행하지 않고 넘어가게 되면 다른 thread는 mutex가 풀릴 때까지 대기해야 합니다.


다음으로 간단한 예제를 통해 동작을 확인해 보도록 하겠습니다.


 - pthread_cond_signal()을 사용한 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <pthread.h>
using namespace std;
 
void *thread(void *);
pthread_t    tid[4];
pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t    cond = PTHREAD_COND_INITIALIZER;
 
int main() {
    int i;
    int id[4];
 
    for(i = 0; i < 4; i++){
        id[i] = i;
        pthread_create(&tid[i],NULL,thread,(void*)&id[i]);
    }
 
    sleep(2);
    pthread_cond_signal(&cond);
 
    for(i = 0; i < 4 ; i++){
        pthread_join(tid[i], NULL);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
 
    return 0;
}
 
void *thread(void *arg){
    //pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond, &mutex);
    cout << "hello, world! from " <<  *((int*)arg) << endl;
    pthread_mutex_unlock(&mutex);
}
cs


 결과 :


 pthread_cond_signal() 함수가 실행되어 하나의 thread만 깨어나 수행을 종료하였습니다. 함수가 끝나기 전 pthread_mutex_unlock() 함수를 실행하였으나 다른 thread들은 깨어나지 못하여 프로그램은 계속 대기상태에 머무르게 됩니다.


 - pthread_cond_broadcast()를 사용한 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <pthread.h>
using namespace std;
 
void *thread(void *);
pthread_t    tid[4];
pthread_mutex_t    mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t    cond = PTHREAD_COND_INITIALIZER;
 
int main() {
    int i;
    int id[4];
 
    for(i = 0; i < 4; i++){
        id[i] = i;
        pthread_create(&tid[i],NULL,thread,(void*)&id[i]);
    }
 
    sleep(2);
    pthread_cond_broadcast(&cond);
 
    for(i = 0; i < 4 ; i++){
        pthread_join(tid[i], NULL);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
 
    return 0;
}
 
void *thread(void *arg){
    //pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond, &mutex);
    cout << "hello, world! from " <<  *((int*)arg) << endl;
    pthread_mutex_unlock(&mutex);
}
cs

결과 :


 pthread_cond_broadcast() 함수가 실행되어 모든 thread가 깨어났음을 확인할 수 있습니다. 깨어난 thread들은 마치 pthread_mutex_lock() 함수가 실행되는 것과 같은 상황이 되어 먼저 mutex를 얻은 thread가 동작을 수행한 후 pthread_mutex_unlock() 함수를 실행하여 깨어난 다른 thread들이 mutex를 잡고 동작을 수행할 수 있도록 해주는 것을 확인하실 수 있습니다.