Linux多线程通信学习之条件变量
从本篇开始对多线程通信的知识点进行整理,本篇主要介绍条件变量,有什么错误和建议请留言指教。有关前文 多线程基础的整理请点此处。
一、条件变量的介绍
条件变量本质也是一个全局变量,它的功能是阻塞线程,直至接收到“条件成立”的信号后,被阻塞的线程才能继续执行。
#include <pthreadtypes.h>
typedef union
{
struct __pthread_cond_s __data;
char __size[__SIZEOF_PTHREAD_COND_T];
__extension__ long long int __align;
} pthread_cond_t;
二、条件变量的创建和使用
相关操作接口有:
函数声明 | 作用 |
int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr) | 初始化条件变量 |
int pthread_cond_destroy (pthread_cond_t *cond) | 销毁条件变量 |
int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t * mutex) | 阻塞线程,等待条件变量被唤醒 |
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) | 阻塞线程,等待了一定时间后若线程未被唤醒则退出 |
int pthread_cond_signal (pthread_cond_t *cond) | 唤醒一个被条件变量阻塞的线程 |
int pthread_cond_broadcast (pthread_cond_t *cond) | 唤醒所有被条件变量阻塞的线程 |
下面这张图很清晰的展示了条件变量的用法和操作过程。
条件变量的使用中存在三个变量,一个互斥锁,一个条件变量,和另外一个需要判断其状态的变量(后面简称其为状态变量),一般执行顺序为:
线程A中
- 对互斥锁加锁
- 判断状态变量状态是否满足某个条件
- 若状态不满足条件则调用pthread_cond_wait函数,该函数中:
- 对互斥锁解锁
- 阻塞当前线程,直到收到pthread_cond_signal信号
- 收到pthread_cond_signal后,再次对互斥锁加锁
- 再次判断状态变量状态是否满足某个条件
- 若状态变量满足条件则对互斥锁解锁,继续往下执行,否则再次进入pthread_cond_wait
线程B中
- 对互斥锁加锁
- 使状态变量满足线程A中的条件
- 调用pthread_cond_signal函数,给线程A发送条件变量信号
- 对互斥锁解锁
将上述逻辑写成代码就是:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 条件变量
UINT32 status = 0; // 状态变量
void thread_A(){
pthread_mutex_lock(&mutex);
while( 100 != status){
pthread_cond_wait(&cond, &mutex)
}
pthread_mutex_unlock(&mutex);
/* 接着执行其它代码 */
}
void thread_B(){
pthread_mutex_lock(&mutex);
status = 100;
pthread_cond_signal(&cond)
pthread_mutex_unlock(&mutex);
/* 继续执行其它代码 */
}
三、代码实例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
/*初始化条件变量*/
void *thread1(void *);
void *thread2(void *);
int i=1, res = 0;
int main(void){
pthread_t t_a, t_b;
pthread_attr_t attr1, attr2;
struct sched_param param;
int other_max = sched_get_priority_max(SCHED_OTHER);
int other_min = sched_get_priority_min(SCHED_OTHER);
int fifo_max = sched_get_priority_max(SCHED_FIFO);
int fifo_min = sched_get_priority_min(SCHED_FIFO);
int rr_max = sched_get_priority_max(SCHED_RR);
int rr_min = sched_get_priority_min(SCHED_RR);
printf("other_max:%d\n", other_max);
printf("other_min:%d\n", other_min);
printf("fifo_max:%d\n", fifo_max);
printf("fifo_min:%d\n", fifo_min);
printf("rr_max:%d\n", rr_max);
printf("rr_min:%d\n", rr_min);
if (0 != pthread_attr_init(&attr1)){
printf("attr1 init error!\n");
exit(0);
}
if (0 != pthread_attr_init(&attr2)){
printf("attr2 init error!\n");
exit(0);
}
/*设置调度策略*/
if (0 != pthread_attr_setschedpolicy(&attr1, SCHED_FIFO)){
printf("attr1 setschedpolicy error!\n");
exit(0);
}
if (0 != pthread_attr_setschedpolicy(&attr2, SCHED_FIFO)){
printf("attr2 setschedpolicy error!\n");
exit(0);
}
/*设置线程1优先级*/
param.sched_priority = 50;
if (0 != pthread_attr_setschedparam(&attr1,¶m)){
printf("attr1 setschedparam error!\n");
exit(0);
}
if (0 != pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED)){
printf("attr1 setinheritsched error!\n");
exit(0);
}
/*设置线程2优先级*/
param.sched_priority = 40;
if (0 != pthread_attr_setschedparam(&attr2,¶m)){
printf("attr2 setschedparam error!\n");
exit(0);
}
if (0 != pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED)){
printf("attr2 setinheritsched error!\n");
exit(0);
}
res = pthread_create(&t_a,&attr2,thread2,(void *)NULL);
/*创建进程t_a*/
if (0 != res){
printf("create thread t_a error! ErrNo : %d\n", res);
exit(0);
}
// sleep(1);
res = pthread_create(&t_b,&attr1,thread1,(void *)NULL);
/*创建进程t_b*/
if (0 != res){
printf("create thread t_a error! ErrNo : %d\n", res);
exit(0);
}
if (0 != pthread_join(t_a, NULL)){
printf("t_a pthread_join error!\n");
exit(0);
}
if (0 != pthread_join(t_b, NULL)){
printf("t_b pthread_join error!\n");
exit(0);
}
if (0 != pthread_attr_destroy(&attr1)){
printf("t_a pthread_attr_destroy error!\n");
exit(0);
}
if (0 != pthread_attr_destroy(&attr2)){
printf("t_b pthread_attr_destroy error!\n");
exit(0);
}
if (0 != pthread_mutex_destroy(&mutex)){
printf("pthread_mutex_destroy error!\n");
exit(0);
}
if (0 != pthread_cond_destroy(&cond)){
printf("pthread_cond_destroy error!\n");
exit(0);
}
exit(0);
}
void *thread1(void *junk){
attach_cpu(0);
for(i=1; i<=9; ){
/*锁住互斥量,使得只有线程2进入wait状态后才能发出signal*/
printf("before thread 1 lock\n");
res = pthread_mutex_lock(&mutex);
if (0 != res){
printf("pthread_mutex_lock error, errorNo: %d\n", res);
exit(0);
}
i++;
if(0 == i%3){
printf("signal\n");
/*条件改变,发送信号,通知t_b进程*/
if (0 != pthread_cond_signal(&cond)){
printf("pthread_cond_signal error!\n");
exit(0);
}
}else{
printf("thread1:%d\n", i);
}
res = pthread_mutex_unlock(&mutex);
if (0 != res){
printf("pthread_mutex_unlock error, errorNo: %d\n", res);
exit(0);
}
usleep(10);
}
}
void *thread2(void *junk){
attach_cpu(0);
while(i < 9){
printf("before lock in thread 2, i : %d\n", i);
res = pthread_mutex_lock(&mutex);
if (0 != res){
printf("pthread_mutex_lock error, errorNo: %d\n", res);
exit(0);
}
if(0 != i%3){
printf("wait\n");
if (0 != pthread_cond_wait(&cond,&mutex)){
printf("pthread_cond_wait error!\n");
exit(0);
}
printf("after wait\n");
}
printf("thread2:%d\n", i);
res = pthread_mutex_unlock(&mutex);
if (0 != res){
printf("pthread_mutex_unlock error, errorNo: %d\n", res);
exit(0);
}
usleep(10);
}
}