1.条件变量
1.条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法。
2.条件变量+互斥锁(一起使用)
线程同步——互斥锁
阻塞线程——条件变量
2.条件变量使用场景举例
举个简单的例子,应用程序A中包含两个线程t1和t2。t1需要在 bool变量test_cond为true时
才能继续执行,而test_cond的值是由t2来改变的,这种情况下,如何来写程序呢?可供选
择的方案有两 种:
第一种是t1定时的去轮询变量test_cond,如果test_cond为false,则继续休眠;如果test_cond为
true,则开始执行。
第二种就是上面提到的条件变量,t1在test_cond为false时调用cond_wait进行等待,t2在改变
test_cond的值后,调用cond_signal,唤醒在等待中的t1,告诉t1 test_cond的值变了,这样t1便可
继续往下执行。
[性能对比分析]
很明显,上面两种方案中,第二种方案是比较优的。在第一种方案中,在每次轮询时,如果t1休
眠的时间比较短,会导致cpu浪费很厉害;如果t1休眠的时间 比较长,又会导致应用逻辑处理不够
及时,致使应用程序性能下降。第二种方案就是为了解决轮询的弊端而生的。
3.相关函数
pthread_cond_t cond; //条件变量类型
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); //初始化
int pthread_cond_destroy(pthread_cond_t *cond); //销毁
//当条件不到来时,仅仅只阻塞一定的时长
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
//当条件不到来时,一直阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
//唤醒[至少一个]阻塞在条件变量上等待的线程
int pthread_cond_signal(pthread_cond_t *cond);
//广播:唤醒[全部]的阻塞在条件变量上等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
注解:pthread_cond_wait 函数剖析
pthread_cond_wait的内部执行原理:
[1]先对mutex解锁,解锁后再阻塞,一直等待条件到来; //条件没到来时,程序阻塞在pthread_cond_wait处
[2]当条件到来(被pthread_cond_signal唤醒)时,解除阻塞,与此同时,
pthread_cond_wait再对mutex加锁;之后执行条件满足的操作
问题:pthread_cond_wait为什么要对mutex解锁?
(1)使得其他线程有机会进入临界区,等待相同的条件
(2)使得其他线程有机会进入临界区,对临界资源进行更改
4.使用条件变量的万能公式
线程A(等待条件的线程)
pthread_mutex_lock(mutex)
while(条件不满足){
pthread_cond_wait(&cond);
}
执行条件满足的操作
pthread_mutex_unlock(mutex)
----------------------------------------
线程B(修改条件的线程)
pthread_mutex_lock(mutex)
修改条件
pthread_mutex_unlock(&mutex);
if(条件满足){
pthread_cond_signal(&cond)
}
疑问:为什么等待条件的线程的代码中使用while,而不是if
防止被虚假的唤醒,当是虚假的唤醒操作时,由于使用的while,因此需要再判断一次,
条件不满足时,继续阻塞。