【线程】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;
};

 

 

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

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

相关文章

基于yolov8的红外小目标无人机飞鸟检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的红外小目标无人机与飞鸟检测系统是一项集成了前沿技术的创新解决方案。该系统利用YOLOv8深度学习模型的强大目标检测能力&#xff0c;结合红外成像技术&#xff0c;实现了对小型无人机和飞鸟等低空飞行目标的快速、准确检测。 YOLOv8作为YOLO系列的…

光伏开发:一分钟生成光伏项目报告

传统光伏项目报告的编制往往需要收集大量数据、进行复杂计算与分析&#xff0c;耗时长且易受人为因素影响。自动生成光伏项目报告&#xff0c;依托大数据、云计算、人工智能等先进信息技术&#xff0c;实现了对光伏项目关键参数的快速分析、评估与预测。 一、核心功能与流程 1…

进程间通信 (一)【管道通信(上)】

目录 1. 概况2. 管道通信的原理2.1 初步理解2.2 深入理解 1. 概况 是什么&#xff1a;两个及以上的进程实现数据层面的交互&#xff0c;称为进程间的通信。 因为进程独立性的存在&#xff0c;所以一个进程无法直接访问另一个进程的数据&#xff0c;即便是父子进程&#xff0c;子…

使用 KuboardSpray 安装kubernetes_v1.23.1

ps:亲测有效,十分方便,记录下来 pps:下面文档来自官网 使用 KuboardSpray 安装kubernetes_v1.23.1 #Kuboard-Spray Kuboard-Spray 是一款可以在图形界面引导下完成 Kubernetes 高可用集群离线安装的工具&#xff0c;开源仓库的地址为 Kuboard-Spray (opens new window) 安…

git push出错Push cannot contain secrets

报错原因&#xff1a; 因为你的代码里面包含了github token明文信息&#xff0c;github担心你的token会泄漏&#xff0c;所以就不允许你推送这些内容。 解决办法&#xff1a; 需要先把代码里面的github token信息删除掉&#xff0c;并且删掉之前的历史提交&#xff0c;只要包…

【深海王国】初中生也能画的电路板?目录合集

Hi٩(๑ ^ o ^ ๑)۶, 各位深海王国的同志们&#xff0c;早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督为大家带来系列文章《初中生也能画的电路板》&#xff0c;帮你一周内快速入门PCB设计&#xff0c;手把手教你从元器件库添加、电路原理图绘制、…

go 运行报错missing go.sum entry for module providing package

运行&#xff1a; #清理go.mod中不再需要的模块&#xff0c;并且会添加缺失的模块条目到go.sum中 go mod tidy

前端vue-实现富文本组件

1.使用wangeditor富文本编辑器 工具网站&#xff1a;https://www.wangeditor.com/v4/ 下载安装命令&#xff1a;npm i wangeditor --save 成品如下图&#xff1a; 组件实现代码 <template><div><!-- 富文本编辑器 --><div id"wangeditor">…

《热血江湖》v23巅峰对决游戏程序(真端+最新官方版本)

《热血江湖》v23巅峰对决游戏程序&#xff08;真端最新官方版本&#xff09; 下载地址&#xff1a; 通过网盘分享的文件&#xff1a;【游戏】《热血江湖》v23巅峰对决游戏程序&#xff08;真端最新官方版本&#xff09; 链接: https://pan.baidu.com/s/18svlGuFnPM9ccwEAb7oBMw…

python-获取浏览器静态/动态素材

f12浏览器中 1&#xff1a;静态爬取 2.动态资源图片获取。斗鱼 3获取视频-抖音 一长串&#xff0c;最后一个http就是视频

相亲交友系统小程序:都市青年的新社交选择

在当今社会&#xff0c;都市青年面临着诸多挑战&#xff0c;其中之一就是如何在繁忙的工作和生活中找到理想的伴侣。相亲交友系统小程序应运而生&#xff0c;成为了都市青年的新社交选择。它不仅简化了传统相亲流程&#xff0c;还利用现代科技手段&#xff0c;如人工智能和大数…

【C++掌中宝】用最少的话让你全方位理解内联函数

文章目录 引言1. 什么是内联函数2. 工作原理3. 内联函数的编程风格4. 使用限制5. 内联函数与宏的比较6. 优缺点7. 何时使用内联函数8. 补充9. 总结结语 引言 在C编程中&#xff0c;函数的调用开销是程序运行效率的一个重要影响因素。为了解决频繁调用函数时的性能问题&#xf…

计算机视觉必备模型YOLO系列模型的知识点,提供YOLOv1-v8模型结构与代码实例

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉必备模型YOLO系列模型的知识点&#xff0c;提供YOLOv1-v8模型结构与代码实例。本文全面介绍了计算机视觉领域中必备的YOLO系列模型&#xff0c;详细梳理了YOLOv1至YOLOv8模型的结构及其演变过程。文章内容…

linux设置常见开机自启动命令

本文介绍了三种开机自启的方式&#xff0c;重点介绍使用systemctl的方式自启动的 方式一、修改 /etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要自己的脚本在开机后被运行的话&#xff0c;可以将自己脚本路径加到…

SQL - 进阶语法(二)约束

1. SQL约束 约束用于约束表中的数据规则&#xff0c;如若存在违反行为&#xff0c;行为会被约束终止。 • NOT NULL 确保列不能有NULL值 如果添加一行新的数据&#xff0c;不能有null值&#xff0c;否则无法添加 新建表格 CREATE TABLE new_table( ID int NOT NULL, NAME …

C语言中易混淆概念的关键字

最快的关键字---- register register&#xff1a; 这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内 存寻址访问以提高效率。注意是尽可能&#xff0c;不是绝对。你想想&#xff0c;一个 CPU 的寄存器也就那么 几个或几十个&#xff0c;你要是定义了很多很…

【环境踩坑系列】centos7安装python3.10.X

前言 虽然centOS8已经发布了相当一段时间了&#xff0c;但是基于稳定性、成熟的社区等原因&#xff0c;大家在选择centOS作为服务器操作系统的时候仍然会选择centOS7作为首选。但是centOS7自带的是python2.7.5&#xff0c;当前大量的python程序要用到的又是python3&#xff0c…

day-60 字符串中最多数目的子序列

思路 由题目可以得出&#xff0c;当字符串开头插入pattern[0]或在字符串结尾插入pattern[1]这两种情况中的一种所得到的子序列数目一定是最多的 解题过程 我们可以遍历字符串&#xff0c;统计pattern[0]的个数&#xff0c;每当遇到一个pattern[1]时&#xff0c;序列数就会加上…

蓝桥杯15届C/C++B组省赛题目

问题描述 小蓝组织了一场算法交流会议&#xff0c;总共有 5050 人参加了本次会议。在会议上&#xff0c;大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手 (且仅有一次)。但有 77 个人&#xff0c;这 77 人彼此之间没有进行握手 (但这 77 人与…

ProgrammerAI—AI辅助编程学习指南

前言 随着AIGC&#xff08;AI生成内容&#xff09;技术的快速发展&#xff0c;诸如ChatGPT、MidJourney和Claude等大语言模型相继涌现&#xff0c;AI辅助编程工具正逐步改变程序员的工作方式。这些工具不仅可以加速代码编写、调试和优化过程&#xff0c;还能帮助解决复杂的编程…