【线程】POSIX信号量---基于环形队列的生产消费者模型
信号量概念
这篇文章是以前写的,里面讲了 System V的信号量的概念,POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
信号量的概念
POSIX信号量的接口
初始化信号量
参数:
pshared:0表示线程间共享,非0表示进程间共享
value:信号量初始值,资源的初始值
销毁信号量
等待信号量,P操作,表示要使用资源,将信号量值加1
发布信号量,V操作,表示资源使用完毕,可以归还资源了,将信号量值加1
基于环形队列的生产消费者模型
生产消费者模型
这篇文章里的生产者消费者模型,是基于一个queue展开了,也就是把queue当成一个整体来看,当成一个资源,我们对他进行加锁保护(锁就相当于二元信号量)。下面我们把这个生产者消费者模型改一下,是基于环形队列的,不把环形队列看成一个整体,把环形队列里的每个块看成很多个资源,这时候线程并发访问时会产生问题,就需要用信号量来解决
环形队列采用数组模拟,用模运算来模拟环状特性,生产者Prpducter向队列里生产任务,消费者Consumer向队列里拿数据
怎么判空和满?
当P,V指向同一个位置的时候,就是空或者满
怎么保证它们不访问同一个位置? 用信号量来管理
生产者关注的是空间资源,消费者关注的是数据资源,这两种资源可以分别用两种信号量来管理 ,假如开始的时候,空间资源是队列的大小,数据资源为0,此时生产者可以申请空间资源信号量成功,他就可以生产,但是消费者申请数据资源信号量时就失败等待,用两个信号量来管理者两个资源就可以很好的让生产者消费者同时访问同一个队列,但是不会访问到同一个位置,就可以很好的解决上面的问题
实现代码
大家可以把他们复制到VS Code下来看
main.cc
#include<iostream>
#include<ctime>
#include<unistd.h>
#include"RingQueue.hpp"
#include"task.hpp"using namespace std;
struct ThreadData
{RingQueue<Task>* rq;string threadname;
};void* Consumer(void* args)
{ThreadData* data=static_cast<ThreadData*>(args);RingQueue<Task>* rq=data->rq;string name=data->threadname;while(true){//消费任务Task t;rq->Pop(&t);//处理任务t.run();printf("消费者得到一个任务:%s,who:%s,结果:%s\n",t.GetTask().c_str(),name.c_str(),t.GetResult().c_str());//用printf输出比较好,不会错乱,cout打印有时会错乱// cout<<"消费者得到一个任务:"<<t.GetTask()<<",who: "<<name<<",结果为:"<<t.GetResult()<<endl;// sleep(1);}return nullptr;
}
void* Producter(void* args)
{ThreadData* data=static_cast<ThreadData*>(args);RingQueue<Task>* rq=data->rq;string name=data->threadname;while(true){//获取数据int data1=rand()%10+1;int data2=rand()%5;char op=opers[rand()%opers.size()];Task t(data1,data2,op);//生产任务rq->Push(t);printf("生产者生产一个任务:%s,who:%s\n",t.GetTask().c_str(),name.c_str());//用printf输出比较好,不会错乱,cout打印有时会错乱// cout<<"生产者生产一个任务:"<<t.GetTask()<<",who: "<<name<<endl;sleep(1);}return nullptr;
}int main()
{srand(time(nullptr));RingQueue<Task>* rq=new RingQueue<Task>(10);pthread_t c[5], p[3];for (int i = 0; i < 3; i++){ThreadData *td = new ThreadData();td->rq = rq;td->threadname = "Productor-" + std::to_string(i);pthread_create(p + i, nullptr, Producter, td);}for (int i = 0; i < 5; i++){ThreadData *td = new ThreadData();td->rq = rq;td->threadname = "Consumer-" + std::to_string(i);pthread_create(c + i, nullptr, Consumer, td);}for (int i = 0; i < 3; i++){pthread_join(p[i], nullptr);}for (int i = 0; i < 5; i++){pthread_join(c[i], nullptr);}return 0;
}
RingQueue.hpp
#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<pthread.h>
#include <semaphore.h>using namespace std;template<class T>
class RingQueue
{
public:void P(sem_t& sem){sem_wait(&sem);}void V(sem_t& sem){sem_post(&sem);}void Lock(pthread_mutex_t& mutex){pthread_mutex_lock(&mutex);}void Unlock(pthread_mutex_t& mutex){pthread_mutex_unlock(&mutex);}
public:RingQueue(int maxcap=5):maxcap_(maxcap),ringqueue_(maxcap),c_index_(0),p_index_(0){sem_init(&cdata_sem_,0,0);sem_init(&pspace_sem_,0,maxcap);pthread_mutex_init(&c_mutex_,nullptr);pthread_mutex_init(&p_mutex_,nullptr);}void Push(const T& in)//生产{P(pspace_sem_);//生产者关注空间资源,申请空间资源,空间资源--Lock(p_mutex_);//下标也是共享资源,需要加锁保护ringqueue_[p_index_]=in;p_index_++;p_index_%=maxcap_;//维持环形特性Unlock(p_mutex_);V(cdata_sem_);//数据资源增多了,数据资源++}void Pop(T* out)//消费{P(cdata_sem_);//消费者关注数据资源,申请数据资源,数据资源--Lock(c_mutex_);//下标也是共享资源,需要加锁保护*out=ringqueue_[c_index_];c_index_++;c_index_%=maxcap_;//维持环形特性Unlock(c_mutex_);V(pspace_sem_);//消费了数据,空间就增多了}~RingQueue(){sem_destroy(&cdata_sem_);sem_destroy(&pspace_sem_);pthread_mutex_destroy(&c_mutex_);pthread_mutex_destroy(&p_mutex_);}private:vector<T> ringqueue_;//用数组模拟环形队列int maxcap_;//环形队列的最大容量int c_index_;//消费者的下标int p_index_;//生产者的下标sem_t cdata_sem_;//消费者关注的数据资源sem_t pspace_sem_;//生产者关注的空间资源pthread_mutex_t c_mutex_;pthread_mutex_t p_mutex_;
};
Task.hpp
#pragma once
#include <iostream>
#include <string>using namespace std;
string opers="+-*/%";enum
{Divzero = 1,Modzero,Unknown
};class Task
{
public:Task(){}Task(int data1, int data2, char op) : _data1(data1), _data2(data2), _op(op), _result(0), _exitcode(0){}void run(){switch (_op){case '+':{_result = _data1+_data2;break;}case '-':{_result = _data1-_data2;break;}case '*':{_result = _data1*_data2;break;}case '/':{if (_data2 == 0) _exitcode = Divzero;else _result = _data1/_data2;break;}case '%':{if (_data2 == 0) _exitcode = Modzero;else _result = _data1%_data2;break;}default:{_exitcode=Unknown;break;}}}void operator()(){run();}string GetResult(){string r=to_string(_data1);r+=_op;r+=to_string(_data2);r+='=';r+=to_string(_result);r+='[';r+=to_string(_exitcode);r+=']';return r;}string GetTask(){string r=to_string(_data1);r+=_op;r+=to_string(_data2);r+="=?";return r;}private:int _data1;int _data2;char _op;int _result;int _exitcode;
};
相关文章:

【线程】POSIX信号量---基于环形队列的生产消费者模型
信号量概念 这篇文章是以前写的,里面讲了 System V的信号量的概念,POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。 信号量的概念 POSIX信号量的接口 初始化…...

Excel 设置自动换行
背景 版本:office 专业版 11.0 表格内输入长信息,发现默认状态时未自动换行的,找了很久设置按钮,遂总结成经验帖。 操作 1)选中需设置的单元格/区域/行/列。 2)点击【开始】下【对齐方式】中的【自动换…...

UNI-SOP使用说明
UNI-SOP提供了两个集成客户端:SpringBoot2.x/JAVA1.8和SpringBoot3.x/JAVA17,满足不同项目的集成需求。 平台接入 使用UNI-SOP之前,业务平台需要进行接入,完成校验后才能正常使用,先引入客户端开发SKD包。 <depen…...

记录-java web 生成并下载zip文件
java生成zip文件,zip文件分两种:一种是包含文件夹、一种是不包含文件夹 生成zip文件的方式 ZipOutputStream zipOutputStream new ZipOutputStream(response.getOutputStream());// 文件夹名称String folder "download/";ZipEntry ze new Z…...
大数据集群部署文档
大数据集群部署文档 注意:需配合大数据集群启动&检查文档进行部署,以便可以检验每一个组件是否部署成功。 文章目录 大数据集群部署文档一、部署前准备1. 确保所有机器可以访问外网2. 配置root用户ssh连接3. 解决Vmware ESXi 6.5 Ubuntu虚拟机ssh连…...

HTML中的表单(超详细)
一、表单 1.语法 <!-- action:提交的地方 method:提交的方式(get会显示,post不会) --> <form action"#" method"get"><p>名字:<input name"name" ty…...

初识 C 语言(一)
目录 一、 第一个 C 程序1. printf() 函数和 stdio.h 头文件2. main() 函数和 return 语句 二、类型和变量1. C 语言中的基本类型2. 变量的创建和命名规则3. 类型和变量的大小 三、printf() 函数和 scanf() 函数1. printf() 函数的使用2. 各种类型的输出格式3. scanf() 函数的使…...

LiveNVR监控流媒体Onvif/RTSP功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大
LiveNVR监控流媒体Onvif/RTSP功能-支持电子放大拉框放大直播视频拉框放大录像视频流拉框放大电子放大 1、视频广场2、录像回看3、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、视频广场 视频广场 -》播放 ,左键单击可以拉取矩形框,放大选中的范围ÿ…...

element ui中当el-dialog需要做全屏时,.fullscreen样式修改问题
element ui 饿了么UI中el-dialog样式修改问题 场景解决方法就是:去掉底部样式中的scoped,然后再进行页面级样式的更改即可。 场景 最近在使用element-ui时,使用到了弹窗组件: element-ui 官网链接地址: element-ui 官网链接地址…...

C++的明星之我是类001
文章目录 类类定义格式访问限定符类域 实例化实例化概念对象大小 this指针两道nt题目题目一题目二 C和C语言实现stack对比 类 类定义格式 新增一个关键字class,后加上类的名字,{}中为类的主体,类中的函数称为类的⽅法或者成员函数定义在类⾯…...

深度学习与应用:行人跟踪
**实验 深度学习与应用:行人跟踪 ** ------ **1、 实验目的** ------ - 了解行人跟踪模型基础处理流程 - 熟悉行人跟踪模型的基本原理 - 掌握 行人跟踪模型的参数微调训练以及推理的能力 - 掌握行人跟踪模型对实际问题的应用能力,了解如何在特定的场景和…...
MySQL | DATE_ADD()函数
题1: 现在运营想要查看用户在某天刷题后第二天还会再来刷题的平均概率。请你取出相应数据。 示例:question_practice_detail iddevice_idquest_idresultdate12138111wrong2021-05-0323214112wrong2021-05-0933214113wrong2021-06-1546543111right2021…...

DVWA 靶场环境搭建
作者:程序那点事儿 日期:2024/09/15 09:30 什么是DVWA: 是OWSASP官方编写的PHP网站,包含了各种网站常见漏洞(漏洞靶场),可以学习攻击及修复方式。 PHP环境包含了,Windows/Apache/Mysql/Php g…...

Autosar学习----AUTOSAR_SWS_BSWGeneral(七)
💥💥🔍 🔍 欢迎来到本博客❤️❤️💥💥 🐡优势:❤️博客内容尽量做到通俗易懂,逻辑清晰。 ⛳️座右铭:恒心,耐心,静心。 ⛳️ 欢迎一起…...

自动化测试框架集成:将Selenium集成到pytest与unittest中
目录 引言 一、Selenium简介 二、Selenium与pytest的集成 1. 安装pytest和Selenium 2. 编写测试用例 3. 运行测试 三、Selenium与unittest的集成 1. 编写测试类 2. 运行测试 四、Selenium自动化测试的最佳实践 1. 使用Page Object模式 2. 合理利用等待机制 3. 跨浏…...

华为GaussDB数据库(单机版)在ARM环境下的安装指南
一、软件版本 机器配置:8核16G,CPU: Huawei Kunpeng 920 2.9GHz操作系统:EulerOS 2.8 64bit with ARM数据库版本:GaussDB Kernel 505.1.0 build 44f4fa53 二、部署流程 2.1 新建用户 ① 以omm用户为例,添加一个omm用…...

计算机网络笔记002
### 课堂讨论对话 **学生A**: 老师,计算机网络的组成是怎样的?🤔 **老师**: 非常好的问题!计算机网络主要由硬件、软件和通信协议三部分组成。我们先从硬件开始讨论吧。 **学生B**: 硬件包括哪些设备呢?ὠ…...

Unity 的Event的Use()方法
对于Event的Use方法,其在调用后将不会再判断同类型的事件 这种情况下,第二个MosueDown不会进入,因为已经Use 如果把Use注释掉 依旧能进入第二个MosueDown 也就是说当使用了Use方法,相同的事件类型不会进第二遍...
数据分析师之Excel数据清洗
前言 目前,掌握一定的Excel技能时,怎么通过自己的技能实现数据分析的操作,就需要进行具体项目的实战,本身数据分析这个行业是非常吃经验的,既然我们是小白入坑,就需要多做实战演练,才能够实际的…...

手机解压软件加密指南:让文件更安全
在数字化时代,文件加密对于保护个人隐私和敏感信息的重要性不言而喻。随着互联网的飞速发展,我们的生活和工作越来越依赖于数字设备和网络。 然而,这也带来了一系列的安全风险,如黑客攻击、数据泄露等。文件加密技术成为了保护我…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...