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;
}
相关推荐
zl_dfq16 小时前
Linux 之 【进程等待】
linux
遇见火星16 小时前
Linux性能调优:理解CPU中的平均负载和使用率
linux·运维·服务器·cpu
Chennnng17 小时前
Ubuntu 安装过程的 6 大常见问题类型
linux·运维·ubuntu
阿干tkl18 小时前
传统网络与NetworkManager对比
linux·网络
Evan芙18 小时前
Linux 进程状态与进程管理命令
linux·运维·服务器
码农12138号19 小时前
Bugku HackINI 2022 Whois 详解
linux·web安全·ctf·命令执行·bugku·换行符
Joren的学习记录19 小时前
【Linux运维进阶知识】Nginx负载均衡
linux·运维·nginx
用户21903265273520 小时前
Java后端必须的Docker 部署 Redis 集群完整指南
linux·后端
胡先生不姓胡20 小时前
如何获取跨系统调用的函数调用栈
linux
里纽斯21 小时前
RK平台Watchdog硬件看门狗验证
android·linux·rk3588·watchdog·看门狗·rk平台·wtd