操作系统(线程管理-通过条件变量实现消费者与生产者模型)

news2024/11/27 20:38:07

 

生产者与消费者模型

img

生产者:生产数据的线程,这类的线程负责从用户端、客户端接收数据,然后把数据Push到存储中介。

消费者:负责消耗数据的线程,对生产者线程生产的数据进行(判断、筛选、使用、响应、存储)处理。

存储中介:也叫数据仓库,是生产者线程与消费者线程之间的数据缓冲区,用于平衡二者之间的生产速度与消耗速度不均衡的问题,通过缓冲区隔离生产者和消费者,与二者直连相比,避免相互等待,提高运行效率。

问题1:生产快于消费,缓冲区满,撑死。

解决方法:负责生产的线程通知负责消费的线程全速消费,然后进入休眠。

问题2:消费快于生产,缓冲区空,饿死。

解决方法:负责消费的线程通知负责生产的线程全速生产,然后进入休眠。

条件变量

条件变量是利用线程间共享的"全局变量"进行同步的一种机制,主要包括两个动作:

1、线程等待"条件变量的条件成立"而休眠;

2、等"条件成立"叫醒休眠的线程。

为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起,一般线程睡入条件变量,伴随着解锁动作,而线程从条件变量醒来时,伴随着加锁动作,如果加锁失败线程进入阻塞状态,而不是睡眠。

// 定义或创建条件变量
pthread_cond_t cond;
​
// 初始化条件变量
int pthread_cond_init (pthread_cond_t* cond,const pthread_condattr_t* attr);
//亦可pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
​
// 使调用线程睡入条件变量cond,同时释放互斥锁mutex
int pthread_cond_wait (pthread_cond_t* cond,pthread_mutex_t* mutex);
​
// 带倒计时的睡眠,时间到了会自动醒来
int pthread_cond_timedwait (pthread_cond_t* cond,
    pthread_mutex_t* mutex,
    const struct timespec* abstime);
​
struct timespec {
    time_t tv_sec;  // Seconds
    long   tv_nsec; // Nanoseconds [0 - 999999999]
};
​
// 从条件变量cond中叫醒一个线程,令其重新获得原先的互斥锁
int pthread_cond_signal (pthread_cond_t* cond);
注意:被唤出的线程此刻将从pthread_cond_wait函数中返回,
但如果该线程无法获得原先的锁,则会继续阻塞在加锁上。
​
// 从条件变量cond中唤醒所有线程
int pthread_cond_broadcast (pthread_cond_t* cond);
​
// 销毁条件变量
int pthread_cond_destroy (pthread_cond_t* cond);

注意:使用互斥锁配合条件变量实现的生产者与消费者模型,能够平衡生产与消费的时间不协调,并且可以最大限度的节约运行资源。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#define STORE_CAP (20)
char store[STORE_CAP];
int front = 0, rear = 0;

void show_store(const char* opt,char data)
{
	for(int i=front; i!=rear; i=(i+1)%STORE_CAP)
	{
		printf("%c ",store[i]);
	}
	printf("%s %c\n",opt,data);
}

// 保护仓库的互斥锁
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 当仓库空时,消费者线程睡入的条件变量 
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
// 当仓库满时,生产者线程睡入的条件变量
pthread_cond_t full = PTHREAD_COND_INITIALIZER;

void* p_run(void* arg)
{
	// 循环的生产数据
	for(;;)
	{
		// 加锁保护仓库
		pthread_mutex_lock(&lock);

		while((rear+1)%STORE_CAP == front)
		{
			// 叫醒所有的消费者线程,全速消费
			pthread_cond_broadcast(&empty);

			// 当前生产者线程睡入 full 条件变量,并解锁
			pthread_cond_wait(&full,&lock);
		}

		// 随机生产一个数据并入库
		char data = rand() % 26 + 'A';
		show_store("<-",data);
		store[rear] = data;
		rear = (rear+1)%STORE_CAP;

		// 叫醒一个消费者线程,开始消费
		pthread_cond_signal(&empty);

		// 解锁
		pthread_mutex_unlock(&lock);

		// 随机休眠一段时间模拟生产数据所消耗的时间
		usleep(rand()%100*5000);
	}
}

void* c_run(void* arg)
{
	// 循环的消费数据
	for(;;)
	{
		// 加锁保护仓库
		pthread_mutex_lock(&lock);

		while(front == rear)
		{
			// 叫醒所有生产者线程,全速生产
			pthread_cond_broadcast(&full);

			// 当前消费者线程睡入 empty 条件变量,并解锁
			pthread_cond_wait(&empty,&lock);
		}

		// 数据出库
		char data = store[front];
		front = (front+1)%STORE_CAP;
		show_store("->",data);

		// 叫醒一个生产者,开始生产数据
		pthread_cond_signal(&full);

		// 解锁
		pthread_mutex_unlock(&lock);

		// 随机休眠一段时间,模拟消费数据所需要的时间
		usleep(rand()%100*5000);
	}
}

int main(int argc,const char* argv[])
{
	size_t pthread_cnt = 10;
	pthread_t tids[pthread_cnt];

	for(int i=0; i<pthread_cnt; i++)
	{
		if(i%2)
			pthread_create(tids+i,NULL,p_run,NULL);
		else
			pthread_create(tids+i,NULL,c_run,NULL);
		pthread_detach(tids[i]);
	}	

	pthread_exit(NULL);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

x264 编码器 SSIM 算法源码分析

SSIM SSIM(Structural Similarity Index)是一种用于衡量两幅图像之间视觉相似度的指标。它不仅考虑了图像的亮度、对比度和饱和度,还考虑了图像的结构信息。SSIM的值介于-1到1之间,值越接近1表示两幅图像越相似。 SSIM是基于以下三个方面来计算的: 亮度(Luminance):比…

【Hot100】LeetCode—560. 和为 K 的子数组

目录 1- 思路前缀和 2- 实现⭐560. 和为 K 的子数组——题解思路 3- ACM 实现 原题链接&#xff1a;560. 和为 K 的子数组 1- 思路 前缀和 ① 借助 HashMap 存储前缀和&#xff1a;Key 为对应的前缀和&#xff0c;Value 为对应的出现次数 hm 初始化放入 (0,1) 代表和为 0 的情…

linux--chrony时间同步以及局域网同步

文章目录 注意Chrony介绍Chrony 支持的系统与联系方式Chrony Git 仓库环境准备服务端确认是否安装chrony如果没有安装&#xff0c;那就执行以下命令进行安装配置文件/etc/chrony.conf命令参数讲解基本用法选项命令系统时钟命令时间源命令NTP 访问命令执行命令参考 客户端确认是…

Java中等题-乘积最大子数组(力扣)

给你一个整数数组 nums &#xff0c;请你找出数组中乘积最大的非空连续 子数组 &#xff08;该子数组中至少包含一个数字&#xff09;&#xff0c;并返回该子数组所对应的乘积。 测试用例的答案是一个 32-位 整数。 示例 1: 输入: nums [2,3,-2,4] 输出: 6 解释: 子数组 […

Telemark电源TT-6E-BEAM SOURCE操作手侧含电路图接线

Telemark电源TT-6E-BEAM SOURCE操作手侧含电路图接线

详解LVS-dr模式

什么是LVS-dr模式 图解 在LVS-DR模式下&#xff0c;负载均衡器&#xff08;也称为调度器&#xff09;接收来自客户端的请求&#xff0c;并根据预设的调度算法将请求转发给后端的真实服务器&#xff08;也称为RS&#xff09;。真实服务器处理完请求后&#xff0c;直接将响应返回…

Jetpack Compose实战教程(六)

Jetpack Compose实战教程&#xff08;六&#xff09; 第六章 没有了margin&#xff0c;如何区分外边距&#xff1f;内边距&#xff1f; 文章目录 Jetpack Compose实战教程&#xff08;六&#xff09;一、前言二、本章目标三、开始编码3.1 特殊情况下的margin3.2 使用padding设…

基于Springboot+netty 的IM聊天室弹幕

代码地址 仓库地址 聊天室 创建springboot项目 因为我的NettyServer 是8080 所以我把服务端口改为了8081 引入netty 依赖 <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.92.Final</versi…

Prometheus+Grafana保姆笔记(1)——Prometheus+Grafana的安装

Prometheus Grafana 的组合在微服务项目中可以完成许多DevOps任务&#xff0c;它们共同提供了强大的监控和可视化功能。 我们陆续介绍Prometheus Grafana 的相关用法。 首先介绍PrometheusGrafana的安装。 安装 Prometheus Prometheus 是GO写的&#xff0c;并不依赖于 Ja…

【深度学习】注意力机制(Transformer)

注意力机制 1.基础概念 1.1 查询、键和值 在人类的注意力方式中&#xff0c;有自主性的与非自主性的注意力提示两种解释方式。所谓自主性注意力提示&#xff0c;就是人本身主动想要关注到的某样东西&#xff1b;非自主性提示则是基于环境中物体的突出性和易见性&#xff0c;…

8.13面试题目

美团商业分析实习生 一、8个球有一个重一点&#xff0c;最少称几次找出 2次 8个球中有一个重一点&#xff0c;最少称2次能找出来。 具体称重步骤如下&#xff1a; 第一次称重&#xff1a;将8个球分成三组&#xff0c;分别为3个球、3个球和2个球。将两组各3个球放在天平的两端…

【搜索二维矩阵】python刷题记录

R4-二分查找专题 直接二维变一维&#xff0c;然后二分查找就可以了 class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:nums[i for row in matrix for i in row]def binfind(the,target):low,high0,len(the)-1while low<high:mid(l…

猫罐头挑选指南!猫咪肥胖有什么危害?健康主食罐挑选攻略!

今天有位铲屎官带着一只17斤的布偶来我们医院。猫猫三岁了&#xff0c;绝育两年&#xff0c;现在因为太胖了&#xff0c;舔毛都不太方便。铲屎官说它平时不太爱动。我给体检后发现甘油三酯高&#xff0c;其他都正常&#xff0c;但必须开始减肥了&#xff0c;猫咪太胖可不好。 一…

江协科技STM32学习笔记

第01章 STM32简介及开发环境搭建 1.1 STM32简介 1.1.1 STM32F103C8T6 系列&#xff1a;主流系列STM32F1 内核&#xff1a;ARM Cortex-M3 主频&#xff1a;72MHz RAM&#xff1a;20K&#xff08;SRAM&#xff09; ROM&#xff1a;64K&#xff08;Flash&#xff09; 供电…

开学季好物分享!全能抗打运动耳机!

大家好&#xff01;开学季来临&#xff0c;在学校的时候&#xff0c;一些运动和体育项目是在所难免的&#xff0c;但是在运动过程中肯定是枯燥无味的&#xff0c;所以这时候就需要一款合适的运动耳机陪伴我们。作为一名对运动耳机有较高要求的学生&#xff0c;我最近发现了一款…

配置jconsole远程监控

# 启动命令 -Djava.rmi.server.hostname192.168.0.67 #java程序所在机器ip -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port8011 #jconsole端口 -Dcom.sun.management.jmxremote.authenticatetrue # 配置为false 就不需要后面的password和access配置 -D…

普元EOS-用户、角色、权限的设计思路

1 前言 普元EOS作为企业应用开发&#xff0c;肯定要对用户、角色、权限这些内容进行管理&#xff0c;本文就描述这些内容EOS的设计思想&#xff0c;以及如何使用这些工具。 2 传统的访问权限控制 先说一个RBAC的概念&#xff0c;就是 Role-Based Access Control&#xff0c;中…

Java Web —— 第五天(请求响应2)

响应数据 ResponseBody 类型:方法注解、类注解 位置: Controller方法上/类上 作用:将方法返回值直接响应&#xff0c;如果返回值类型是 实体对象/集合&#xff0c;将会转换为JSON格式响应 说明: RestController Controller ResponseBody ; package com.example.springbo…

嘉实基金“青黄不接”:董事长赵学军被调查,明星经理基金绿油油

尚未实现“打造中国版的贝莱德”之梦&#xff0c;手握万亿资产管理规模的嘉实基金便“出事”了。 近日&#xff0c;嘉实基金在官网披露了一则临时公告&#xff0c;称其于2024年8月9日从相关方面获悉&#xff0c;该公司董事长赵学军因个人问题正配合有关部门调查。目前&#xf…

录音怎么转换成mp3格式?6款免费音频转换mp3的软件大公开!(赶紧收藏)

录音怎么转换成mp3格式&#xff1f;录音是我们日常记录生活和工作的常见方式之一。然而&#xff0c;不同的音频格式往往会带来兼容性和播放上的困难。如果您曾因为无法播放某个录音而烦恼&#xff0c;或者希望能够方便地将录音转换成mp3格式&#xff0c;那么本文就能告诉您答案…