linux---生产者和消费者模型

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。

一、堵塞队列

(1)三种关系

生产者vs生产者:互斥(加锁)

消费者vs消费者:互斥(加锁)

生产者vs消费者:互斥和同步(加锁和条件变量)

(2)代码实现

Makefile

test:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f test

BlockQueue.hpp

#include<iostream>
#include<queue>
#include<unistd.h>
#define M 10
template<class T>
class BlockQueue{
public:
BlockQueue(T cap=M)
:_capacity(M)
{pthread_mutex_init(&_mutex,nullptr);pthread_cond_init(&_pcond,nullptr);pthread_cond_init(&_ccond,nullptr);}bool IsFull()
{return q.size()==_capacity;
}
bool empty()
{return q.size()==0;
}void Push( T in)
{pthread_mutex_lock(&_mutex);//if(!IsFull())//可能出现伪唤醒while(IsFull())//健壮性{pthread_cond_wait(&_pcond,&_mutex);}q.push(in);std::cout<<"push:"<<in<<std::endl;sleep(1);pthread_cond_signal(&_ccond);pthread_mutex_unlock(&_mutex);
}void Pop()
{pthread_mutex_lock(&_mutex);while(empty())//if(!empty())//如果这里使用if判断的话,可能出现伪唤醒问题。{pthread_cond_wait(&_ccond,&_mutex);}auto n=q.front();std::cout<<"pop:"<<n<<std::endl;sleep(1);q.pop();pthread_cond_signal(&_pcond);pthread_mutex_unlock(&_mutex);}~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_pcond);
pthread_cond_destroy(&_ccond);
}private:pthread_mutex_t _mutex;pthread_cond_t _pcond;pthread_cond_t _ccond;int _capacity=M;std::queue<T> q;};

Main.cc 

#include<pthread.h>
#include"BlockQueue.hpp"
#include<iostream>
void* consumer(void* argv)
{BlockQueue<int>* q=static_cast<BlockQueue<int>*>(argv);int i=0;while(true){  q->Pop();}return nullptr;
}
void * productor(void* argv)
{BlockQueue<int>* q=static_cast<BlockQueue<int>*>(argv);while(true){int data=rand()%10+1;q->Push(data);}
return nullptr;
}int main()
{srand((unsigned)time(NULL)^getpid()^pthread_self());pthread_t c,p;BlockQueue<int>* bq=new BlockQueue<int>();pthread_create(&c,nullptr,consumer,bq);pthread_create(&p,nullptr,productor,bq);pthread_join(c,nullptr);pthread_join(p,nullptr);return 0;
}

(3)总结

以上是单生产和单消费,对于多生产和多消费也是可以的,因为是同一个队列,同一把锁,同一把锁就决定了,生产者和生产者,消费者和消费者之间就是互斥的,生产者和消费者的条件变量提供了同步。

队列中的数据也可以是任务,堵塞队列可以实现高并发高效率,在与每个线程都拿到了自己的任务

并且处理任务,处理任务也是需要时间的,这个决定了,每个线程拿到任务都在跑自己的任务代码,实现高并发。同时条件变量让生产者和消费者进行同步,保证了安全性。

1.消费者和生产者调度优先级

如果消费者线程先调度,队列为空,消费者就会在条件变量下进行等待,等生产者生产商品了,就会唤醒消费者进行消费。

2.如何控制生产消费的节奏

我们可以通过sleep控制。比如消费者消费进行休眠的话,可以给生产者足够的时间进行生产

3.伪唤醒

如果用if来判断队列为空可能会出现伪唤醒,有些线程处于等待堵塞,竞争锁的状态,一旦队列为空而线程竞争到了锁就会出现队列为空依然进行pop的现象。

while(true)可以提供检查,if判断可能有风险。


环形队列

(1)POSIX信号量

posix和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步.

快速认识接口:

(1)初始化

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

参数: pshared:0表示线程间共享,非零表示进程间共享value:信号量初始值

(2)销毁

int sem_destroy(sem_t *sem);
 

(3)等待

功能:等待信号量,会将信号量的值减1

int sem_wait(sem_t *sem);//p()
 

(3)通知

功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。int sem_post(sem_t *sem);//V()
 

三种关系

(2)对于环形队列,生产者和消费者就有两种场景会指向同一个位置。要么为空,要么为满,其他情况不会指向同一个位置。

1.如果队列为空,只能让生产者先生产,消费者不可以消费---------互斥

2.如果队列为满,只能让消费者先消费,然后到生产者生产---------同步

3.其余情况,消费者都是在生产者后面的,两个位置不同,即使pop和push同时进行,也是安全的,这个就是多线程高并发可以进入临界区的原因。

如何实现多线程中的生产者和生产者,消费者和消费者的互斥问题,对于循环队列,我们要定义两把锁,一个是push队列的锁,一个是pop队列的锁。pv操作是原子性的,让生产者和消费者进行同步其中又可以体现互斥。

代码实现

makefile

ringtest:Main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f ringtest

Main.cc

#include<iostream>
#include<pthread.h>
#include"RingQueue.hpp"
#include<pthread.h>void* producter(void* args)
{while(true){ RingQueue<int>* rq=static_cast<RingQueue<int>*>(args);int n=1;n=rand()%3+1;rq->Push(n);}}
void* consumer(void* argv)
{while(true)
{RingQueue<int>* q=static_cast<RingQueue<int>*>(argv);int date=0;q->Pop(&date);}}int main()
{srand(time(nullptr));pthread_t p,c;
pthread_mutex_t pm,cm;LockGuard pmutex(&pm),cmutex(&cm);RingQueue<int> ringqueue(cmutex,pmutex);
pthread_create(&p,nullptr,consumer,&ringqueue);
pthread_create(&c,nullptr,producter,&ringqueue);pthread_join(p,nullptr);pthread_join(c,nullptr);return 0;
}

RingQueue.hpp 

#include<vector>
#include<iostream>
#include"LockGuard.hpp"
#include<unistd.h>
const int Size =10;
template<class T>
class RingQueue{
private:void P(sem_t& sem){sem_wait(&sem);}void V(sem_t& sem){sem_post(&sem);}
public:
RingQueue(LockGuard c,LockGuard p,int s=Size)
:size(s),pmutex(p),cmutex(c),q(s),ppose(0),cpose(0)
{
sem_init(&psem,0,size);
sem_init(&csem,0,0);}// 生产
void Push(const T& in)
{// 先加锁,还是先申请信号量?先申请信号量,效率高。申请到资源的线程,只有竞争到锁,就可以生产了。P(psem);{pmutex;q[ppose] = in;std::cout<<"生产:"<<in<<std::endl;ppose++;ppose %=size;}V(csem);
}
void Pop(T* out)
{P(csem);{cmutex;*out = q[cpose];sleep(1);std::cout<<"消费:"<<*out<<std::endl;cpose++;cpose %=size;}V(psem);}
~RingQueue()
{sem_destroy(&psem);sem_destroy(&csem);
}private:int size;std::vector<int> q;int ppose;//生产者位置int cpose;//消费者位置sem_t psem;//生产者信号量sem_t csem;//消费者信号量LockGuard pmutex;LockGuard cmutex;};
#pragma once
#include<pthread.h>
#include <semaphore.h>
class Mutex{
public:Mutex(pthread_mutex_t* mutex):_Mutex(mutex){pthread_mutex_init(_Mutex,nullptr);}void Lock(){pthread_mutex_lock(_Mutex);}void unlock(){pthread_mutex_unlock(_Mutex);}~Mutex(){pthread_mutex_destroy(_Mutex);}private:pthread_mutex_t* _Mutex;
};class LockGuard{
public:LockGuard(pthread_mutex_t* lock):mutex(lock){mutex.Lock();}~LockGuard(){mutex.unlock();}private:Mutex mutex;};

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

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

相关文章

2024年海南省三支一扶报名指南,照片要求

2024年海南省三支一扶报名指南&#xff0c;照片要求 一、考试时间安排&#xff1a; 报名时间&#xff1a;6月1日8:00至6月7日18:00 准考证打印时间&#xff1a;6月17日8:00 考试时间&#xff1a;6月22日 二、招聘人数 海南省计划招募390名高校毕业生

STM32_IIC

1、IIC简介 I2C&#xff0c;即Inter IC Bus。是由Philips公司开发的一种串行通用数据总线&#xff0c;主要用于近距离、低速的芯片之间的通信&#xff1b;有两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff09;用于通信双方时钟的同步、SDA&#xff08;Serial Data…

JVM之【执行引擎】

执行引擎 执行引擎是JVM的核心组件之一&#xff0c;它负责将Java字节码文件转换为机器指令并执行。这一过程涉及多个组成部分&#xff0c;各部分协同工作来完成字节码到机器指令的转换和执行。以下是执行引擎的主要组成部分及其作用&#xff1a; 1. 解释器&#xff08;Interp…

vue.js框架快速入门

Vue.js是一个渐进式JavaScript框架&#xff0c;用于构建用户界面和单页应用程序。以下是Vue.js快速入门的基本步骤和概念&#xff1a; 1. 环境准备 确保你的计算机上安装了Node.js&#xff0c;它包括npm&#xff08;Node Package Manager&#xff09;&#xff0c;用于管理项目…

友善RK3399v2平台利用rkmpp实现硬件编解码加速

测试VPU 编译mpp sudo apt update sudo apt install gcc g cmake make cd ~ git clone https://github.com/rockchip-linux/mpp.git cd mpp/build/linux/aarch64/ sed -i s/aarch64-linux-gnu-gcc/gcc/g ./arm.linux.cross.cmake sed -i s/aarch64-linux-gnu-g/g/g ./arm.lin…

如何学习ai agent?

如何学习Agent&#xff0c;推荐阅读《动手做AI Agent》这本书。 推荐理由&#xff1a; 1&#xff1a;一本书能够全方位了解并探索Agent的奥秘&#xff01; &#xff08;1&#xff09;Agent的发展进程。 &#xff08;2&#xff09;可以帮我们做哪些事&#xff1a;自动办公&am…

TypeScript 中的迭代器和生成器

1. 迭代器 迭代器是一种对象&#xff0c;它提供了一种统一的方式来访问集合中的元素&#xff0c;而不暴露集合的内部结构。在 TypeScript 中&#xff0c;迭代器通过实现 Iterator 接口来定义。 interface Iterator<T> {next(): IteratorResult<T>; }interface It…

Liunx登录时相关bash配置文件(登录脚本)

profile类的文件&#xff1a;设定环境变量&#xff0c;运行命令或脚本 bashrc类的文件&#xff1a;定义命令别名 全局配置&#xff1a; /etc/profile /etc/profile.d/*.sh /etc/bashrc 个人配置文件: ~/.bash_profile ~/.bashrc 用户登录时加载bash配置文件的过程&#xff0c;…

码随想录算法训练营第二十四天| 77. 组合

77. 组合 - 力扣&#xff08;LeetCode&#xff09; class Solution {ArrayList<Integer> path new ArrayList<>();ArrayList<List<Integer>> result new ArrayList<>();public List<List<Integer>> combine(int n, int k) {if(n &…

升级Jenkins从2.263.3到2.440.2

升级Jenkins从2.263.3到2.440.2 ###任何一次升级前&#xff0c;先做整体备份&#xff0c;同时最好对plugins目录和config.xml单独备份。 ###对于任何一次插件安装&#xff0c;务必安装前先备份当前的plugins目录&#xff0c;这是血的教训。升级过程 1、 升级2.263.3到2.263.4…

15-通过JS代码处理窗口滚动条

selenium并不是万能的&#xff0c;页面上有些操作无法实现时&#xff0c;就需要借助JS代码来完成了。selenium提供了一个方法&#xff1a;execute_script()&#xff0c;可以执行JS脚本代码。 比如&#xff1a;当页面上的元素超过一屏后&#xff0c;想操作屏幕下方的元素&#x…

MyBatis查询功能

MyBatis的各种查询功能 1、若查询出的数据只有一条 &#xff08;1)可以通过实体类对象或者集合接收 (2)可以通过List集合接收 (3&#xff09;可以通过map集合接收 结果&#xff1a;{password123456, sex女, id8, age22, email1234qq.com, usernameadmin4} 2、若查询出来的数据有…

[leetcode hot 150]第一百零八题,将有序数组转换为二叉搜索树

题目&#xff1a;给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡二叉搜索树。 给定一个有序的整数数组,我们需要构建一棵平衡的二叉搜索树。平衡二叉树是指任意一个节点的左右子树的高度差不超过1。 由于给定的数组是有序的…

阿里云计算学习笔记(一)

运维管理 运维管理&#xff08;Operation and Maintenance Management, 简称O&M管理&#xff09;是指通过科学的管理方法和技术手段&#xff0c;对IT系统和基础设施进行监控、维护、优化和保障&#xff0c;以确保系统的高可用性、稳定性、安全性和性能。运维管理涵盖了硬件…

Prime1 - 提权的另一种解法,彻底搞懂OpenSSL解密渗透提权,超强思路版。

提权枚举 现在我们直接从低权限用户开始&#xff1b;我们先按照提权步骤&#xff0c;简单的系统枚举 虽然我们知道可以利用系统版本低进行内核提权&#xff0c;内核提权虽然比较快比较方便&#xff0c;但也比较暴力&#xff0c;缺点非常明显&#xff1b;很容易导致系统服务中…

【云原生】Kubernetes----POD控制器

目录 引言 一、Pod控制器概述 二、Pod控制器的种类 &#xff08;一&#xff09;ReplicaSet &#xff08;二&#xff09;Deployment &#xff08;三&#xff09;StatefulSet &#xff08;四&#xff09;DaemonSet &#xff08;五&#xff09;Job 三、使用POD控制器 &a…

【Seafile】Seafile容器版文件删除后存储空间不释放问题解决

Seafile是一款非常优秀的网盘系统&#xff0c;我们可以根据官方文档&#xff0c;在本地虚拟机研究Seafile免费版的安装和使用&#xff0c;安装建议采用使用docker容器的方式。 不过在使用过程中&#xff0c;刚接触的小伙伴可能会遇到这样的问题&#xff1a; 删除网盘里面的文…

数据赋能(106)——方法论:描述模式与AI——批量处理

在一系列相似的主题内容进行编写时&#xff0c;可以采用批处理的方式。主要步骤如下&#xff1a; 1、确定主题内容模式。如&#xff1a;各个主题的概述中&#xff0c;包括如下内容模式项目&#xff1a;工作主要目的、工作重要性、工作核心内容、工作本质 2、确定模式的各项内…

C++设计模式-状态模式

文章目录 28. 状态模式 运行在VS2022&#xff0c;x86&#xff0c;Debug下。 28. 状态模式 状态模式让一个对象的行为随着内部状态的改变而改变&#xff0c;而该对象也像换了类一样。应用&#xff1a;如在游戏开发中&#xff0c;游戏有不同场景&#xff0c;如主菜单、开始、战斗…

在leafet上画圆、多边形、线、矩形

在leaflet上画圆、多边形、线、矩形 <template><div id"map" class"map"></div> </template><script> import L from leaflet; export default {data () {return {myGroup: ,};},mounted () {this.initMaps()this.huizhiro…