文章目录
- 条件变量
- 概述
- 条件变量的优缺点
- 条件变量相关函数
- pthread_cond_init函数
- pthread_cond_destroy函数
- pthread_cond_wait函数
- pthread_cond_signal函数
- 测试生产者和消费者模型
条件变量
概述
与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁!
条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量的两个动作:
- 条件不满, 阻塞线程
- 当条件满足, 通知阻塞的线程开始工作
条件变量的类型: pthread_cond_t。
条件变量的优缺点
相较于mutex而言,条件变量可以减少竞争。
如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果汇聚(链表)中没有数据,消费者之间竞争互斥锁是无意义的。
有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。
条件变量相关函数
pthread_cond_init函数
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化一个条件变量
参数:cond:指向要初始化的条件变量指针。attr:条件变量属性,通常为默认值,传NULL即可也可以使用静态初始化的方法,初始化条件变量:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:成功:0失败:非0错误号
pthread_cond_destroy函数
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁一个条件变量
参数:cond:指向要初始化的条件变量指针
返回值:成功:0失败:非0错误号
pthread_cond_wait函数
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
功能:阻塞等待一个条件变量a) 阻塞等待条件变量cond(参1)满足b) 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);a) b) 两步为一个原子操作。c) 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);
参数:cond:指向要初始化的条件变量指针mutex:互斥锁
返回值:成功:0失败:非0错误号
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct.*restrict abstime);
功能:限时等待一个条件变量
参数:cond:指向要初始化的条件变量指针mutex:互斥锁abstime:绝对时间
返回值:成功:0失败:非0错误号
abstime补充说明:
struct timespec {time_t tv_sec; /* seconds */ // 秒long tv_nsec; /* nanosecondes*/ // 纳秒
}
time_t cur = time(NULL); //获取当前时间。
struct timespec t; //定义timespec 结构体变量t
t.tv_sec = cur + 1; // 定时1秒
pthread_cond_timedwait(&cond, &t);
pthread_cond_signal函数
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒至少一个阻塞在条件变量上的线程
参数:cond:指向要初始化的条件变量指针
返回值:成功:0失败:非0错误号
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒全部阻塞在条件变量上的线程
参数:cond:指向要初始化的条件变量指针
返回值:成功:0失败:非0错误号
测试生产者和消费者模型
#include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <unistd.h>
#include <pthread.h>pthread_cond_t cond;
pthread_mutex_t mutex;typedef struct _node_t
{int data;struct _node_t *next;
}node_t;node_t *head = NULL;void *producer(void *arg)
{node_t *new = NULL;while(1){pthread_mutex_lock(&mutex);new = malloc(sizeof(node_t));if(NULL == new){printf("malloc failed\n");pthread_mutex_unlock(&mutex);break;}memset(new, 0, sizeof(node_t));new->data = random() % 100 + 1;new->next = head;head = new;printf("-------生产者生产了产品 %d\n", new->data);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(NULL == head){//阻塞在条件变量pthread_cond_wait(&cond, &mutex);}//删除链表第一个节点tmp = head;head = head->next;printf("消费者消费产品 %d\n", tmp->data);free(tmp);pthread_mutex_unlock(&mutex);sleep(random() % 3 + 1);}pthread_exit(NULL);
}
int test01()
{int ret = -1;pthread_t tid1 = -1;pthread_t tid2 = -1;srandom(time(NULL));ret = pthread_mutex_init(&mutex, NULL);if(0 != ret){printf("pthread_mutex_init failed\n");goto err0;}ret = pthread_cond_init(&cond, NULL);if(0 != ret){printf("pthread_cond_init failed\n");goto err0;}//生产者线程ret = pthread_create(&tid1, NULL, producer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}//消费者线程ret = pthread_create(&tid1, NULL, customer, NULL);if(0 != ret){printf("pthread_create failed\n");goto err0;}pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
err0:return 1;
}