1、条件变量的概念
一个线程A的执行需要另一个线程B来唤醒,否则A挂起等待。线程B可以产生线程A继续执行的信号。条件变量常用在共享数据状态变化的场景中,例如:生产则和消费者问题。POSIX线程库提供了条件变量这种同步机制。使用条件变量需要联合互斥锁一起使用。
2、如何声明一个条件变量
#include <pthread.h>pthread_cond_t cond;
3、如何初始化一个条件变量
//静态初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//动态初始化条件变量
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);//结合互斥锁的条件变量初始化结构变量
typedef struct{pthread_mutex_t mutex;//互斥pthread_cond_t cond;//条件int value;//变量资源
}mutexcond_t;mutexcond_t mymutexcond = {PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER,0};
静态初始化的条件变量不需要销毁,动态初始化的条件变量需要销毁,销毁函数声明如下:
int pthread_cond_destroy(pthread_cond_t *cond);
4、如何阻塞含条件变量的线程
线程执行等待条件变量后,将一直阻塞或计时阻塞,两个函数接口:pthread_cond_wait,pthread_cond_timewait。
int pthread_cond_wait(pthread_cond_t * restrict cond, pthread_mutex_t *restrict mutex);int pthread_cond_timewait(pthread_cond_t * restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
关键字:restrict,限制,表明指针修饰的指针是访问一个数据对象的惟一且初始的方式。
pthread_cond_wait传入两个参数,一个条件变量cond指针和一个互斥变量mutex指针。互斥变量的作用是防止多线程同时调用pthread_cond_wait形成竞争。一旦调用cond_wait会临时对cond进行加锁,当条件不满足时,会阻塞并挂起当前等待,内核自动释放mutex锁给其他线程使用当前cond,从而防止多线程在等待同一个cond时,无法充分利用资源。
5、如何唤醒等待条件变量的线程
//只唤醒一个等待条件变量的线程
int pthread_cond_signal(pthread_cond_t *cond);//唤醒所有等待条件变量的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
6、总结用法
条件变量和互斥锁的用法比较绕,总结一下就是。
- 调用pthread_cond_wait之前,必须给互斥锁上锁pthread_mutex_lock(&mutex)。
- 一旦执行到pthread_cond_wait,如果没有收到pthead_cond_signal发出的cond信号,pthread_cond_wait会自动解锁,并一直阻塞。
- 一旦pthread_cond_wait收到pthread_cond_signal发出的cond信号,pthread_cond_wait会自动加锁,因此,条件变量满足后进入临界区,执行结束需要pthread_mutex_unlock(&mutex)解锁。
// 线程1
{pthread_mutex_lock(&mutex);...pthread_cond_signal(&cond);//唤醒等待cond的线程...pthread_mutex_unlock(&mutex);
}// 线程2
{pthread_mutex_lock(&mutex);...pthread_cond_wait(&cond,&mutex);//等待条件变量...pthread_mutex_unlock(&mutex);
}