当一个线程互斥的访问某个变量时,它可能发现在其他线程改变状态之前,它什么也做不了。例如,一个线程访问队列时,发现队列为空,它只能等待,直到其它线程将一个节点添加到队列中,这种情况就需要用到条件变量。
    一、条件变量函数
    
    (1)初始化
    
    int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condatrr_t *restrict attr);
    
    参数:
    
    cond:要初始化的条件变量;
    
    attr:NULL。
   
    (2)销毁
    
    int pthread_cond_destroy(pthread_cond_t *cond);
   
    (3)等待条件满足
    
    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
    
    参数:
    
    cond:要在这个条件变量上等待;
    
    mutex:互斥量,后面详细解释。
   
    (4)唤醒等待
    
    int pthread_cond_broadcast(pthread_cond_t *cond);
    
    int pthread_cond_signal(pthread_cond_t *cond);
   
【例】
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex;
void *route1(void *arg)
{
    while(1){
        pthread_cond_wait(&cond, &mutex);
        printf("action\n");
    }
}
void *route2(void *arg)
{
    while(1){
        pthread_cond_signal(&cond);
        sleep(1);
    }
}
int main(void)
{
    pthread_t tid1, tid2;
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&tid1, NULL, route1, NULL);
    pthread_create(&tid2, NULL, route2, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}
    运行结果:
    
    
   
    二、 为什么pthread_cond_wait需要互斥量?
    
    1)条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程。
    
    2)条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据。
   
    【例】错误的设计——先上锁,发现条件不满足,解锁,然后等待在条件变量上
    
    pthread_mutex_lock(&mutex);
    
    while(condition_is_false){
    
    pthread_mutex_unlock(&mutex);
    
    //解锁之后,等待之前,条件可能已经满足,信号已经发出,但是该信号可能被错过
    
    pthread_cond_wait(&cond);
    
    pthread_mutex_lock(&mutex);
    
    }
    
    pthread_mutex_unlock(&mutex);
    
    1)由于解锁和等待不是原子操作。调用解锁之后,pthread_cond_wait之前,如果已经有其他线程获取到互斥量,摒弃条件满足,那么pthread_cond_wait将错过这个信号,可能会导致线程阻塞在这个pthread_cond_wait。所以解锁和等待必须是一个原子操作。
    
    2)int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);进入该函数后,会去看条件量等于0不?等于,就把互斥量变成1,直到cond_wait返回后,把条件量改成1,把互斥量恢复成原样。
   
    条件变量使用规范
    
    1)等待条件代码
   
pthread_mutex_lock(&mutex);
while(条件为假)
    pthread_cond_wait(&cond);
修改条件
pthread_mutex_unlock(&mutex);
2)给条件发送信号代码
pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);
    【例】生产者和消费者模型
    
    图示如下:
    
    
   
代码如下
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 2
struct msg{
    struct msg *next;
    int num;
};
struct msg *head = NULL;
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_t threads[CONSUMERS_COUNT+PRODUCERS_COUNT];
void *consumer(void *p)
{
    int num = *(int *)p;
    free(p);
    struct msg *mp;
    for( ; ; ){
        pthread_mutex_lock(&mutex);
        while(head == NULL){
            printf("%d end wait a condition...\n", num);
            pthread_cond_wait(&cond, &mutex);
        }
        printf("%d end wait a condition...\n", num);
        printf("%d begin consumer product...\n", num);
        mp = head;
        head = mp -> next;
        pthread_mutex_unlock(&mutex);
        printf("Consume %d\n", mp->num);
        free(mp);
        printf("%d end consume product...\n", num);
        sleep(rand()%5);
    }
}
void *producer(void *p)
{
    struct msg *mp;
    int num = *(int *)p;
    free(p);
    for( ; ; ){
        printf("%d begin produce product...\n", num);
        mp = (struct msg*)malloc(sizeof(struct msg));
        mp ->num = rand()%1000 + 1;
        printf("produce %d\n", mp->num);
        pthread_mutex_lock(&mutex);
        mp -> next = head;
        head = mp;
        printf("%d end produce product...\n", num);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        sleep(rand()%5);
    }
}
int main()
{
    srand(time(NULL));
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    int i;
    for(i=0; i<CONSUMERS_COUNT; i++)
    {
        int *p = (int *)malloc(sizeof(int));
        *p = i;
        pthread_create(&threads[i], NULL, consumer, (void*)p);
    }
    for(i=0; i<PRODUCERS_COUNT; i++)
    {
        int *p = (int*)malloc(sizeof(int));
        *p = i;
        pthread_create(&threads[CONSUMERS_COUNT+i], NULL, producer, (void*)p);
    }
    for(i = 0; i<CONSUMERS_COUNT; i++)
        pthread_join(threads[i], NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
}
    运行结果为: