一、条件变量概述
与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁!
条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量的两个动作:
①. 条件不满, 阻塞线程
②. 当条件满足, 通知阻塞的线程开始工作
条件变量的类型: pthread_cond_t。
二、pthread_cond_init函数
1.函数原型
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
2.功能
初始化一个条件变量
3.参数
①. cond:指向要初始化的条件变量指针。
②. attr:条件变量属性,通常为默认值,传NULL即可。
也可以使用静态初始化的方法,初始化条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
4.返回值
成功:0 ; 失败:非0错误
三、pthread_cond_destroy函数
1.函数原型
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
2.功能
销毁一个条件变量
3.参数
①. cond:指向要初始化的条件变量指针。
4.返回值
成功:0 ; 失败:非0错误
四、pthread_cond_wait函数
1.函数原型
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
2.功能
阻塞等待一个条件变量
①. 阻塞等待条件变量cond(参1)满足
②. 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
①②两步为一个原子操作。
③. 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex)。
3.参数
①. cond:指向要初始化的条件变量指针
②. mutex:互斥锁
4.返回值
成功:0 ; 失败:非0错误
五、pthread_cond_timedwait函数(不常用)
1.函数原型
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
2.功能
用于条件变量等待,并允许设置超时时间。
3.参数
①. cond:要等待的条件变量。
②. mutex:与条件变量关联的互斥锁,调用前需已加锁。
③. abstime:绝对超时时间(从Epoch开始的秒和纳秒)。
struct timespec {
time_t tv_sec; /* seconds */ // 秒
long tv_nsec; /* nanosecondes*/ // 纳秒
}
4.返回值
成功:0 ; 失败:非0错误
六、pthread_cond_signal函数
1.函数原型
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
2.功能
唤醒至少一个阻塞在条件变量上的线程。
3.参数
①. cond:指向要初始化的条件变量指针。
4.返回值
成功:0 ; 失败:非0错误
七、pthread_cond_broadcast函数
1.函数原型
int pthread_cond_broadcast(pthread_cond_t *cond);
2.功能
唤醒全部阻塞在条件变量上的线程
3.参数
①. cond:指向要初始化的条件变量指针。
4.返回值
成功:0 ; 失败:非0错误
八、函数的示例
1.条件变量的示例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
//互斥锁
pthread_mutex_t mutex;
//条件变量
pthread_cond_t cond;
int flag = 0;
//改变条件
void *fun1(void *arg)
{
while(1){
//加锁
pthread_mutex_lock(&mutex);
//改变变量
flag = 1;
//解锁
pthread_mutex_unlock(&mutex);
//发送信号
pthread_cond_signal(&cond);
sleep(1);
}
return NULL;
}
//等待条件
void *fun2(void *arg)
{
while(1){
//加锁
pthread_mutex_lock(&mutex);
if(flag == 0){
pthread_cond_wait(&cond, &mutex);
}
printf("条件为真,线程2执行...\n");
flag = 0;
//解锁
pthread_mutex_unlock(&mutex);
}
return NULL;
}
int main()
{
int ret;
pthread_t tid1, tid2;
//初始化互斥锁
ret = pthread_mutex_init(&mutex, NULL);
if(ret != 0){
printf("pthread_mutex_init failed...\n");
return 1;
}
//初始化条件变量
ret = pthread_cond_init(&cond, NULL);
if(ret != 0){
printf("pthread_cond_init failed...\n");
return 1;
}
pthread_create(&tid1, NULL, fun1, NULL);
pthread_create(&tid2, NULL, fun2, NULL);
//回收线程
ret = pthread_join(tid1, NULL);
if(ret != 0){
printf("pthread_join tid1 failed...\n");
return 1;
}
ret = pthread_join(tid2, NULL);
if(ret != 0){
printf("pthread_join tid2 failed...\n");
return 1;
}
//回收互斥锁
pthread_mutex_destroy(&mutex);
//回收条件变量
pthread_cond_destroy(&cond);
return 0;
}
2.生产者与消费者条件变量模型
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
typedef struct _node_t{
int data;
struct _node_t *next;
}node_t;
node_t *head = NULL;
void *producer(void *arg)
{
while(1){
pthread_mutex_lock(&mutex);
node_t *new = malloc(sizeof(node_t));
if(new == NULL){
printf("malloc failed...\n");
break;
}
memset(new, 0, sizeof(node_t));
new->data = random()%100 + 1;
new->next = NULL;
printf("生产者生产%d\n", new->data);
//头插
new->next = head;
head = new;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
sleep(random()%3+1);
}
pthread_exit(NULL);
}
void *customer(void *arg)
{
node_t *tmp = NULL;
while(1){
pthread_mutex_lock(&mutex);
if(head == NULL){
printf("没有消费任务......\n");
pthread_cond_wait(&cond, &mutex);
}else{
tmp = head;
head = head->next;
printf("消费者消费%d\n", tmp->data);
free(tmp);
}
pthread_mutex_unlock(&mutex);
sleep(random()%3+1);
}
pthread_exit(NULL);
}
int main(){
pthread_t tid1 = -1, tid2 = -1;
int ret = -1;
srandom(getpid());
ret = pthread_mutex_init(&mutex, NULL);
if(ret != 0){
printf("pthread_mutex_init failed...\n");
return 0;
}
ret = pthread_cond_init(&cond, NULL);
if(ret != 0){
printf("pthread_cond_init failed...\n");
return 0;
}
pthread_create(&tid1, NULL, producer, NULL);
pthread_create(&tid2, NULL, customer, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}