pthread cond wait 와 cond signal 에 대해서 잘 모르겠어요.
글쓴이: ddoraee / 작성시간: 수, 2014/05/28 - 7:43오전
#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++; } }
위 코드는 간단한 thread 동기화 예제 코드 인데요 .
여기서 ping/pong 동기화를 위해 pthread cond wait 이랑 signal을 쓰는데요.
이부분에서 개념이 잘 안잡히네요.
ping 에서 cond signal(&gcond)를 호출하는 데요. 여기서 어떤일이 일어나는지 잘 모르겠습니다. 그리고 바로 그다음에
cond wait을 부르는 데요. 이게 쓰레드는 즉시 mutex를 release 하고 다시 reacquire 한다고 이해했는데.
여기에선 어떻게 이해해야되는지 또 감이 안잡히네요.
혹시 ping 이랑 pong 부분에서 cond_wait이랑 cond_signal을 써서 동기화가 어떻게 이루어지는지 설명좀 해주실수 있나요?
Forums:
조건변수 이해하기에 썩 좋은 예제는 아니군요..
조건변수 이해하기에 썩 좋은 예제는 아니군요.. http://stackoverflow.com/a/16524148/1242128 이런 식으로 실제 조건을 나타내는 변수를 함께 쓰는 게 정석입니다. 조건변수 시그널은 상태를 유지하지 않고, pthread_cond_wait()은 시그널을 받지 않고서도 깨어나는 경우가 있기 때문입니다(spurious wakeup).
pthread_cond_signal(조건변수)는 해당 조건변수를 기다리며 block 상태인 쓰레드가 있으면 (그 중에 스케쥴러가 골라서) 깨워줍니다. 질문하신 것에 비추어 설명하면, ping 쓰레드에서 pthread_cond_signal(&gcond)가 불리면, 만약 pong 쓰레드가 gcond를 기다리고 있었다면, 그걸 깨워주겠죠. 그렇지 않다면 그냥 무시됩니다! pong의 while문 안의 맨 처음 뮤텍스 잡기 직전에 usleep(3000)을 넣어서 실행해보시고, 무슨 문제가 생긴건지, 이런 문제를 방지하려면 어떻게 해야하는지 잘 생각해보세요..
pthread_cond_wait(조건변수, 뮤텍스) 동작도 나름의 이해가 필요합니다. 이 함수 호출 전에 쓰레드는 해당 뮤텍스를 이미 잡고 있어야 하는데, pthread_cond_wait()을 호출하면 잡고 있던 뮤텍스를 놓고 block 상태로 들어갑니다. 나중에 누군가 pthread_cond_signal() 혹은 _broadcast()를 불러주거나, 또는 기타의 이유로 깨어나면, 다시 한번 해당 뮤텍스를 (경쟁하여) 잡고 반환합니다.
그러니 질문하신 것에 비추어 다시 설명하면, ping()의 while문은 gmutex를 잡은 상태로 pong이 대기중이었다면 깨워주고, (pong이 깨워줄때까지) 대기상태로 들어가며 gmutex를 놓고, 대기상태에서 깨어나면서 다시 gmutex를 잡으며 앞의 과정을 반복하는 거죠.
그런데, pong이 아직 대기 상태로 들어가기도 전에 ping이 먼저 signal을 던지고 대기상태로 들어가면 어떤 일이 벌어질까요? 그래서 앞에서 usleep을 넣어보고 실행해보시라 한 겁니다. (혹은, 뭐, ㅎㅎ thread_list에 pong을 먼저 넣는 대신 ping을 먼저 넣어보실수도 있겠구요)
하여간 그렇습니다.
pthread_cond_wait()과 pthread_cond_signal의 맨페이지에 나와 있는 팩트들을 잘 읽어보시고,
http://stackoverflow.com/questions/8594591/why-does-pthread-cond-wait-have-spurious-wakeups 를 읽어보시면 spurious wakeup이 뭔지 뿐만 아니라 조건변수를 어떤 식으로 써야하는지 좀 더 세밀한 이해를 얻으실 수 있을 겁니다. 멀티쓰레드 프로그래밍은 어렵지요..
감사합니다.
제가 좀더 깊이 생각을 안해본거 같네요. wait 이 mutex를 놓고 다시 잡는 거에서 헷갈렸는데 거기서 이해가 되니깐 cond 부분 이해하기가 수월했어요. 좋은 정보 감사해요.
만약 pong 에 usleep3000 삽입된다면.
만약 pong while 문 mutex 앞에 슬립이 들어가면 pong 이 mutex 을 잡지 못하고 cond_wait 함수를 부르지 못한채 ping으로 넘어가 ping에서 signal(gcond)를 하지만 대기중인 쓰레드가 없다고 판단하고 무시. 그리고
ping 의 wait 이 호출 되서 ping 쓰레드는 블락이 되고 mutex를 release 하게 되고. 다시 usleep에서 깨어난 pong 쓰레드가 mutex를 잡지만 다시 wait 함수가 호출되서 둘다 블락 되고 cond signal을 기다리는 상황이 되게 되는거죠?
댓글 달기