apue学习之使用条件变量实现生产者消费者模型
一、条件变量
条件变量提供了一种线程同步的机制,当条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。条件本身是由互斥量保护的,所以线程在改变条件状态之前必须先锁住互斥量。虽然互斥锁实现了线程之间的互斥,但是互斥锁也有不足之处,它只能表示两种状态:上锁和非上锁。但是假如有线程A拿着锁进入临界区,并在临界区休眠了。而此时正在等待该锁的线程就会不断轮询,查看锁是否已经被释放。当线程A释放锁后,所有在该锁上阻塞的线程都会变成可运行状态,第一个变成可运行状态的线程会先获得锁,其他线程会继续等待直到变为可用。
引入条件变量一个就是为了避免为了查看条件是否成立而不断轮询的情况,这样也提高了效率;另一个就是为了防止竞争,条件变量用来阻塞一个线程,当条件不满足时,线程往往会解开互斥锁并等待条件发生变化,一旦有某个线程改变了条件变量,它会通知该条件变量下的一个或多个正在被该条件变量阻塞的线程,这些线程会重新上锁并检测条件是否成立。
总结:互斥锁实现的是线程之间的互斥,条件变量实现的是线程之间的同步。
使用互斥量之前需要初始化,静态分配的条件变量可以使用两种初始化,动态分配的条件变量需要函数初始化。在释放条件变量底层的内存空间之前,可以使用pthread_cond_destroy函数进行反初始化。
#include<pthread.h>
//利用宏进行初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//初始化函数
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
//反初始化函数
int pthread_cond_destroy(pthread_cond_t *cond);
使用pthread_cond_wait函数等待条件变量为真
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
传递给pthread_cond_wait的互斥量对条件进行保护。调用者把锁住的互斥量传给函数,函数然后自动把调用线程放到等待条件的线程列表上,对互斥量解锁。这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。
1、调用pthread_cond_wait前需要先对互斥量mutex上锁,才能把&mutex传入pthread_cond_wait函数
2、在pthread_cond_wait函数内部,会首先对传入的mutex解锁
3、当等待的条件到来后,pthread_cond_wait函数内部在返回前会去锁住传入的mutex
有两个函数可以通知线程条件已经满足:
//至少唤醒一个等待该条件的线程
int pthread_cond_signal(pthread_cond_t *cond);
//唤醒等待该条件的所有线程
int pthread_cond_broadcast(pthread_cond_t *cond);
二、条件变量实现生产者消费者模型
// File Name: pthread_cond.c
// Author: AlexanderGan
// Created Time: Fri 03 Jul 2020 02:37:01 PM CST
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<pthread.h>
int start = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//链表节点
typedef struct SourceInfo{
int num;
struct SourceInfo* next;
}SoInfo;
SoInfo* head = NULL;
void* thr_productor(void* arg)
{
//为链表添加数据
while(1)
{
SoInfo* prod = malloc(sizeof(SoInfo));
prod->num = start++;
printf("--func: %s --tid: %lu --%d\n",__FUNCTION__,pthread_self(),prod->num);
pthread_mutex_lock(&mutex);
prod->next = head;
head = prod;
pthread_mutex_unlock(&mutex);
//通知条件变量条件满足
pthread_cond_signal(&cond);
sleep(rand()%2);
}
}
void* thr_customer(void* arg)
{
SoInfo* prod = NULL;
while(1)
{
//取出链表数据
pthread_mutex_lock(&mutex);
while(head == NULL){
//必须先加锁
pthread_cond_wait(&cond,&mutex);
}
prod = head;
head = head->next;
printf("--func: %s --tid: %lu --%d\n",__FUNCTION__,pthread_self(),prod->num);
pthread_mutex_unlock(&mutex);
free(prod);
sleep(rand()%2);
}
}
int main(int argc, char* argv[]){
pthread_t tid[3];
pthread_create(&tid[0],NULL,&thr_productor,NULL);
pthread_create(&tid[1],NULL,&thr_customer,NULL);
pthread_create(&tid[2],NULL,&thr_customer,NULL);
for(int i = 0; i < 3;i++){
pthread_join(tid[i],NULL);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0 ;
}
运行效果: