11.4 Linux_线程_条件变量

概述

条件变量的作用:

条件变量和互斥量配合使用,主要应用于生产者和消费者问题。

这种问题也是一种临界资源的问题,但与互斥量一文中 "写文件" 这种资源不同。文件是一直存在的临界资源,而生产者的资源不是一直存在,资源的产生需要一些条件。条件变量实现了在等待生产者时,消费者进入休眠状态,提高运行效率。

条件变量使用方法:

1、初始化互斥量、条件变量

2.1 生产者:加锁互斥量->生产资源->发送信号给条件变量->解锁互斥量

2.2 消费者:加锁互斥量->无资源时等待条件变量->消费资源->解锁互斥量

相关函数

1、初始化

cpp 复制代码
//动态初始化
int pthread_cond_init(pthread_cond_t *restrict cond,
                      const pthread_condattr_t *restrict attr);
//静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

返回值:成功返回0,失败返回错误码

cond:要初始化的条件变量

attr:条件变量属性,NULL代表默认属性

2、销毁

cpp 复制代码
int pthread_cond_destroy(pthread_cond_t *cond);

返回值:成功返回0,失败返回错误码

cond:要销毁的条件变量

3、等待资源

cpp 复制代码
//等待临界资源,阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond,
                      pthread_mutex_t *restrict mutex);
//等待临界资源,一段时间后退出阻塞
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
                           pthread_mutex_t *restrict mutex,
                           const struct timespec *restrict abstime);

cond:等待哪一个条件变量的信号

mutex:与条件变量搭配使用的互斥量

注意:该函数在没有资源时,会解锁互斥量,并把本线程休眠。当接收到资源时,会解除休眠,并再次把互斥量上锁

4、发送信号

cpp 复制代码
//单个发送信号,代表资源来了,所有线程竞争该资源
int pthread_cond_signal(pthread_cond_t *cond);
//广播发送信号,代表资源来了
int pthread_cond_broadcast(pthread_cond_t *cond);

cond:要向哪一个条件变量发送信号

注意:当 "发送信号" 比 "等待资源" 早时,"等待资源" 是接收不到信号的,这会导致信号丢失。这意味着当运行到 "等待资源" 时,会进入阻塞,直到第二次 "发送信号" 到来

生产者消费者示例代码

cpp 复制代码
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t mutex;//互斥锁
pthread_cond_t cond;//条件变量
//资源
struct resource{
	char num;
	struct resource* pNext;
};
struct resource Head;
struct resource* pTail;
//消费者
void* consumer(void* arg){
	struct resource* pResource = NULL;
	while(1){
		//1.加锁互斥量
		pthread_mutex_lock(&mutex);
		//2.无资源时等待条件变量,有资源时不断消耗资源
		while(Head.pNext == NULL){//while的作用:防止信号为广播时产生惊群效应
			pthread_cond_wait(&cond,&mutex);
		}
		//3.消费资源
		pResource = Head.pNext;
		Head.pNext = Head.pNext->pNext;
		if(Head.pNext == NULL){
			pTail = &Head;
		}
		printf("consumer:num = %d\n",pResource->num);
		free(pResource);
		//4.解锁互斥量
		pthread_mutex_unlock(&mutex);
		sleep(1);
	}
}
//生产者
void* producer(void* arg){
	struct resource* pNew = NULL;
	int i = 0;
	while(1){
		//1.加锁互斥量
		pthread_mutex_lock(&mutex);
		//2.生产资源
		if((pNew = malloc(sizeof(struct resource))) == NULL){
			printf("malloc err\n");
			pthread_exit(NULL);
		}
		pNew->num = i++;
		pNew->pNext = NULL;
		pTail->pNext = pNew;
		pTail = pNew;
		printf("producer:num = %d\n",pNew->num);
		//3.发送信号给条件变量
		pthread_cond_signal(&cond);
		//4.解锁互斥量
		pthread_mutex_unlock(&mutex);
		sleep(1);
	}
}
int main(){

	pthread_t tid;
	Head.pNext = NULL;
	pTail = &Head;
	//初始化互斥锁和条件变量
	pthread_mutex_init(&mutex,NULL);
	pthread_cond_init(&cond,NULL);

	//创建线程
	if(pthread_create(&tid,NULL,producer,NULL) != 0){
		perror("pthread_create");
		pthread_detach(tid);
		return -1;
	}
	if(pthread_create(&tid,NULL,consumer,NULL) != 0){
		perror("pthread_create");
		return -1;
	}
	while(1);
	//销毁互斥锁和条件变量
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);
	return 0;
}
相关推荐
H.2019 分钟前
centos7执行yum操作时报错Could not retrieve mirrorlist http://mirrorlist.centos.org解决
linux·centos
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
helloliyh1 小时前
Windows和Linux系统安装东方通
linux·运维·windows
van叶~3 小时前
Linux探秘坊-------4.进度条小程序
linux·运维·小程序
秋风&萧瑟3 小时前
【数据结构】顺序队列与链式队列
linux·数据结构·windows
我科绝伦(Huanhuan Zhou)3 小时前
Linux 系统服务开机自启动指导手册
java·linux·服务器
hunter2062065 小时前
ubuntu终端当一段时间内没有程序运行时,自动关闭终端。
linux·chrome·ubuntu
代码讲故事7 小时前
从Windows通过XRDP远程访问和控制银河麒麟ukey v10服务器,以及多次连接后黑屏的问题
linux·运维·服务器·windows·远程连接·远程桌面·xrdp
qq_243050799 小时前
irpas:互联网路由协议攻击套件!全参数详细教程!Kali Linux入门教程!黑客渗透测试!
linux·网络·web安全·网络安全·黑客·渗透测试·系统安全
IT北辰9 小时前
Linux下 date时间应该与系统的 RTC(硬件时钟)同步
linux·运维·实时音视频