条件变量是Linux线程同步的一种机制,与互斥量一起使用时,允许线程以无竞争的方式等待特定条件的发生
[TOC]
关键函数
初始化与注销
1 | #include <pthread.h> |
注意:
- 只有在没有线程在该条件变量上等待时,才可以注销条件变量,否则会返回
EBUSY
Linux
在实现条件变量时,并没有为条件变量分配资源,所以在注销一个条件变量时,只需要注意该变量是否仍有等待线程即可
线程等待
1 | #include <pthread.h> |
执行过程如下:
- 调用者把锁住的互斥量传给函数,然后函数自动把调用线程放到等待条件的线程列表上
- 对互斥量进行解锁,线程挂起进入等待(不占用
CPU
时间) - 函数被唤醒返回时,会自动对互斥量进行加锁
pthread_cond_timedwait
只是多了一个等待超时时间,通过timespec
指定,超时返回错误ETIMEDOUT
线程唤醒
1 | #include <pthread.h> |
pthread_cond_signal
至少能唤醒一个等待该条件的线程pthread_cond_broadcast
则能唤醒等待该条件的所有线程需要注意的是,一定要在改变条件状态以后再给线程发信号
示例
示例代码可参考我的github,由于篇幅原因,不在此贴出
一些思考
条件变量实质是什么
条件变量实质是利用线程间共享的全局变量进行同步的一种机制
互斥量保护的是什么
示例中的相关代码
1 | pthread_mutex_lock(&(test->mut)); |
互斥量是用来保护条件test->condition
在读取时,它的值不被其它线程修改,如果条件成立,则此线程进入等待条件的线程队列,对互斥量进行解锁并开始等待
为什么用while来判断条件
如上面的代码所示,使用while
对条件进行判断的原因如下:
- 若先解锁互斥量,再唤醒等待线程,则条件可能被其它线程更改,使得等待条件再次成立,需要继续等待
pthread_cond_wait
可能存在意外返回的情况,则此时条件并没有被更改,需要继续等待。造成意外返回的原因是
Linux
中带阻塞功能的系统调用都会在进程收到signal
后返回
先唤醒线程还是先解锁
示例代码:
情况一:先唤醒
1
2
3
4pthread_mutex_lock(&(test->mut));
test->condition = 1
pthread_cond_signal(&(test->cond));
pthread_mutex_unlock(&(test->mut));情况二:先解锁
1
2
3
4pthread_mutex_lock(&(test->mut));
test->condition = 1
pthread_mutex_unlock(&(test->mut));
pthread_cond_signal(&(test->cond));两种情况各有缺点:
- 情况一在唤醒等待线程后,再解锁,使得等待线程在被唤醒后试图对互斥量进行加锁时,互斥量还未解锁,则线程又进入睡眠,待互斥量解锁成功后,再次被唤醒并对互斥量加锁,这样就会发生两次上下文切换,影响性能
- 情况二在唤醒等待线程前先解锁,使得其它线程可能先于等待线程获取互斥量,并对条件进行更改,使得条件变量失去作用