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…

友善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…

码随想录算法训练营第二十四天| 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 &…

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

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

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

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

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; 删除网盘里面的文…

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

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

Houdini的PythonScript基本使用

前言 Houdini内置了Python脚本和相应的编辑器, 很多时候想灵活的制作各种Houdini工具, 基本是必须用到 Python。Houdini官方的python提供了非常完善的接口, 比如可以创建各种节点&#xff0c;连接各种节点&#xff0c;遍历节点各种数据&#xff0c;遍历节点参数等等。 Houdin…

word避免画质画质模糊方法

问题描述&#xff1a;   近期写文档时会高频率贴图&#xff0c;粘图过程中发现Word会自动压缩图片画质&#xff0c;而且压缩得很严重&#xff0c;下面是一幅图被压缩前后的画质对比 &#xff08;图片压缩前&#xff09; &#xff08;图片压缩后&#xff09; 解决方案&#x…

基于JSP的九宫格日志网站

你好呀&#xff0c;我是学长猫哥&#xff01;如果有需求可以文末加我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;浏览器/服务器&#xff08;B/S&#xff09;结构 系统展示 首页 管理员功能模块 用户功能模块 摘要 本…

GPT-4o VS GPT-3.5 完胜

前言&#xff1a; 最近&#xff0c;GPT-4o已经限时免费开放了&#xff0c;试了一下&#xff0c;然后&#xff0c;说我的时间到了&#xff0c;然后&#xff0c;有给我转到3.5&#xff0c;正好遇到一个问题做一下对吧&#xff0c;感觉4O完胜啊。3.5还是很好胡诌&#xff0c;也就…

[Algorithm][动态规划][子序列问题][最长定差子序列][最长的斐波那契子序列的长度]详细讲解

目录 1.最长定差子序列1.题目链接2.算法原理详解3.代码实现 2.最长的斐波那契子序列的长度1.题目链接2.算法原理详解3.代码实现 1.最长定差子序列 1.题目链接 最长定差子序列 2.算法原理详解 思路&#xff1a; 确定状态表示 -> dp[i]的含义 以i位置元素为结尾的所有子序列…

11.2 选择排序

目录 11.2 选择排序 11.2.1 算法特性 11.2 选择排序 选择排序&#xff08;selection sort&#xff09;的工作原理非常简单&#xff1a;开启一个循环&#xff0c;每轮从未排序区间选择最小的元素&#xff0c;将其放到已排序区间的末尾。 设数组的长度为 &#x1d45b;…

华东师范大学研究团队《Ecology Letters 》揭示植物如何改变其物候以响应全球变化

自工业革命以来&#xff0c;人类活动导致多种环境因子同时发生变化&#xff0c;包括气候变暖、降水模式改变、氮沉降增加和大气CO2升高。这些变化预计会影响植物生命周期事件的季节时序—植物物候&#xff08;Nature Reviews Earth & Environment | 傅伯杰院士团队发文阐述…

[C][栈帧]详细讲解

目录 1.栈帧1.进程地址空间2.栈帧说明 2.认识相关寄存器3.认识相关汇编命令4.过程理解5.栈帧总结6.补充 1.栈帧 1.进程地址空间 .进程地址空间 2.栈帧说明 调用函数&#xff0c;形成栈帧函数返回&#xff0c;释放栈帧局部变量是存放在栈区上的栈区内存的使用习惯是&#xff…

BPTT算法详解:深入探究循环神经网络(RNN)中的梯度计算【原理理解】

引言 在深度学习领域中&#xff0c;我们经常处理的是独立同分布&#xff08;i.i.d&#xff09;的数据&#xff0c;比如图像分类、文本生成等任务&#xff0c;其中每个样本之间相互独立。然而&#xff0c;在现实生活中&#xff0c;许多数据具有时序结构&#xff0c;例如语言模型…