条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁定互斥量以后才能计算条件。
条件变量使用之前必须首先初始化,pthread_cond_t数据类型代表的条件变量可以用两种方式进行初始化
可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量
但是如果条件变量是动态分配的,可以使用pthread_cond_destroy函数对条件变量进行去除初始化(deinitialize)。
1、互斥锁为防止多个线程同时访问同一个共享量,而条件变量允许一个线程就某个共享变量(或其他共享资源)的状态变化通知其他线程,并让其他线程等待(阻塞于)这一通知。条件变量总是结合互斥锁一起使用,条件变量就共享变量的状态改变发出通知,而互斥锁则提供对该共享变量访问的互斥
2、API:
2.1初始化条件变量
头文件
#include<pthread.h>
函数原型
int pthread_cond_init(pthread_cond_t *cv,const pthread_condattr_t *cattr);
返回值
成功返回 0, 否则返回错误码
参数
cv: 需初始化的条件变量
cattr: 设置的条件变量属性
2.2销毁条件变量
头文件
#include<pthread.h>
函数原型
int pthread_cond_destory(pthread_cond_t *cond);
返回值
成功返回 0, 否则返回错误码
参数
cond: 需销毁的条件变量
说明:
只有在没有线程在该条件变量上等待时,才可以注销条件变量,否则会返回 EBUSY
2.3等待条件变量
头文件
#include<pthread.h>
函数原型
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
返回值
成功返回 0, 否则返回错误码
参数
cond: 等待的条件变量
mutex: 所使用的互斥锁
说明:
线程阻塞在等待条件变量的状态中
pthread_cond_wait等待条件变为真。如果在给定的时间内条件不能满足,那么会生成一个代表一个出错码的返回变量。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传给函数。函数把调用线程放到等待条件的线程列表上,然后对互斥量解锁,这两个操作都是原子操作。这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。
2.4唤醒条件变量
头文件
#include<pthread.h>
函数原型
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
返回值
成功返回 0, 否则返回错误码
参数
cond: 要唤醒的条件变量
在调用 pthread_cond_wait 之前,若没有互斥锁的保护,则线程有可能达等待信号发生阶段前收到信号,结果自然是信号成功的被忽略掉,程序阻塞在等待信号中。
这两个函数可以用于通知线程条件已经满足。即广播
pthread_cond_signal函数将唤醒等待该条件的某个线程
pthread_cond_broadcast函数将唤醒等待该条件的所有进程
注意一定要在改变条件状态以后再给线程发信号。
2.5、demo条件变量
两个线程的执行,只采取互斥锁的情况下两个线程运行的先后是不确定的。为了确保在全局变量g_data等于3时,会执行线程1。所以对线程2进行加锁,即使先运行线程1,当线程1运行1次后会转为运行线程2,在线程2中进行对g_data++判断当等于3时,线程2会触发会触发线程1的等待,转到线程1运行,线程1执行1次后又会被线程2强先运行
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<errno.h>
#define uint unsigned long
int g_data = 0;
pthread_mutex_t mutex;//声明全局变量 互斥量mutex类型
//互斥量初始化方法一:PTHREAD_MUTEX_INITIALIZER
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
//条件变变量使用特定的数据类型:pthread_mutex_t
pthread_cond_t cond; //声明cond
//条件变量初始化方法一:PTHREAD_COND_INITIALIZER
//pthread_cond_t mutex = PTHREAD_COND_INITIALIZER
void *func1(void *arg)
{
printf("t1:%ld thread is create\n",(uint)pthread_self());
printf("t1:data is %d\n",*((int *)arg));
while(1)
{
pthread_cond_wait(&cond,&mutex); //等待 等待触发
printf("t1:===================\n");
printf("t1:%d\n",g_data);
g_data = 0; //重新将g_data=0
sleep(1);
static int cnt = 0;
if(cnt++ == 4)
{
exit(0);//运行5次退出程序
}
}
}
void *func2(void *arg)
{
printf("t2:%ld thread is create\n",(uint)pthread_self());
printf("t2:data is %d\n",*((int *)arg));
while(1)
{
printf("t2: %d\n",g_data);
pthread_mutex_lock(&mutex);//加锁
g_data++;
if(g_data == 3)
{
pthread_cond_signal(&cond); //触发
}
pthread_mutex_unlock(&mutex);//解锁
sleep(1);
}
}
main函数部分与互斥锁demo相同,把注释掉的条件变量的创建及注销接触即可
//创建条件变量 及初始化
pthread_cond_init(&cond,NULL);
//注销条件变量
pthread_cond_destroy(&cond);