互斥量防止多个线程同时访问同一共享变量。条件变量则是在此之外的拾遗补缺。条件变量允许一个线程就某个共享变量(或其他共享资源)的状态变化通知其他线程,并让其他线程等待(堵塞于)这一通知。
条件变量总是结合互斥量使用。条件变量就共享变量的状态改变发出通知,而互斥量则提供对该共享变量访问的互斥。
有关互斥量的总结点击查看:linux线程同步:互斥锁
条件变量的数据类型是pthread_count_t.如同互斥量一样,条件变量的分配,有静态和动态之分.
条件变量初始化:
类似于互斥量,使用条件变量前必须对其初始化。
由静态分配的条件变量可以通过静态赋值法进行初始化,可参考下面的例子:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
经由动态分配的条件变量,使用函数pthread_cond_init()对条件变量进行动态初始化。需要使用pthread_cond_init()的情况类似于使用pthread_mutex_init()来动态初始化互斥量的情况。亦即,对自动或动态分配的条件变量进行初始化时,或是对未采用默认属性经由静态分配的条件变量进行初始化时,必须使用pthread_cond_init()。
#include<pthread.h>
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t* attr);
参数cond表示将要初始化的目标条件变量。attr参数来判定条件变量的属性。若attr为NULL,则使用默认属性初始化,因为大部分都是用到的默认属性,所以其他属性不在这里介绍了。
通知和等待条件变量:
条件变量主要操作是发送信号(signal)和等待(wait)。发送信号操作即通知一个或多个处于等待状态的线程,某个共享变量的状态已经改变。等待操作是指在收到一个通知前一直处于阻塞状态。
函数phtread_cond_signal()和pthread_cond_broadcast()均可针对由参数cond所指定的条件变量而发出信号。pthread_cond_wait()函数将阻塞一线程,直至收到条件变量cond的通知。
#include<pthread.h>
int pthread_cond_signal(pthread_cont_t* cond);
int pthread_cond_broadcast(pthread_cont_t* cond);
pthread_cond_signal()函数只保证唤醒最多一条遭到阻塞的线程,而pthread_cond_broadcast()则会唤醒所有遭到阻塞的进程。
应注意的是,调用pthread_cond_wait()函数时,实际会执行以下三个步骤:
1.解锁互斥量mutex
2.堵塞调用线程,直至另一线程就条件变量cond发出信号
3.重新锁定mutex
所以,当另一个线程调用pthread_cond_signal()去唤醒另一个调用pthread_cond_wait()函数阻塞的线程时,应该先调用pthread_mutex_unlock将mutex解锁,再调用pthread_cond_signal().此时pthread_cond_wait()才能正常执行第三步。
另一点应注意的,线程调用thread_cond_wait()时,应用while循环语句控制对thread_cond_wait()的调用,而不是if语句。例如:while(avail==0) thread_cond_wait();
因为,当代码从thread_cond_wait()返回时,并不能确定判断条件的状态,所以应该立刻重新检查判断条件,在条件不满足的情况下继续休眠等待。
(其他线程可能会率先醒来,也许有多个进程在等待获取与条件变量相关的互斥量。即使就互斥量发出通知的线程将判断条件置为预期状态,其他线程依然很可能率先获取互斥量并改变相关共享变量的状态,进而改变判断条件的状态)