最近在看clamd的代码,其中thrmgr.c中多次使用了条件变量,写一小段代码来复习一下条件变量的用法。
条件变量主要应用在多线程的同步,比如用于生产者消费者模型。当没有产出的时候,为了避免消费者空转耗费cpu,可以使用条件变量进行阻塞。在有产出的时候进行通知,进行消费。
使用中通常和互斥锁配合使用,主要为了避免非原子操作,导致cond_wait错过cond_signal,出现预期外的错误。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
static void *worker(void *arg)
{
pthread_mutex_lock(&mutex);
printf("start cond wait.\n");
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
printf("thread exit.\n");
}
int main()
{
pthread_t thr_id[10];
int i = 0;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
for(i=0; i<4; i++)
{
if(pthread_create(&thr_id[i], NULL, worker, NULL) != 0)
{
printf("create thr:%d failed.\n", i);
}
}
sleep(1);
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
printf("signal\n");
sleep(1);
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
printf("broadcast\n");
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
}
打印的结果是
start cond wait.
start cond wait.
start cond wait.
start cond wait.
# after 1 second
signal
thread exit.
# after 1 second
broadcast
thread exit.
thread exit.
thread exit.
没有用过条件变量的同学可能会对输出有疑问,为什么worker线程中加了锁,其他的线程还能阻塞到pthread_cond_wait之前呢。原因是pthread_cond_wait包含了两个操作,一是释放锁,二是等待信号。所以,在pthread_cond_wait的时候,该线程是没有上锁的状态。