【Linux】POSIX信号量和基于环形队列的生产消费者模型

目录

写在前面的话

什么是POSIX信号量

POSIX信号量的使用

基于环形队列的生产消费者模型


 

写在前面的话

        本文章主要先介绍POSIX信号量,以及一些接口的使用,然后再编码设计一个基于环形队列的生产消费者模型来使用这些接口。

        讲解POSIX信号量时,首先需要对信号量有一定的了解,大家可以去看我的这一篇文章:systemV信号量,文章的前面我详细的说明了什么是信号量以及对它的理解。


什么是POSIX信号量

        POSIX信号量(POSIX semaphore)是一种线程同步机制,用于管理共享资源的并发访问。POSIX信号量是基于POSIX标准定义的一组函数和数据类型,旨在提供跨平台的线程同步能力。

        POSIX信号量允许线程在访问共享资源之前获取一个信号量,通过增加或减少信号量值来控制对资源的访问。当信号量值大于零时,线程可以获取资源并继续执行。当信号量值为零时,线程将被阻塞,直到其他线程释放资源并增加信号量的值。这样可以有效地实现对共享资源的互斥访问和线程之间的同步。


POSIX信号量的使用

  • sem_init()用于初始化一个信号量对象。

函数原型如下:

int sem_init(sem_t *sem, int pshared, unsigned int value);
  • pshared:0表示线程间共享,非零表示进程间共享
  • value:信号量初始值
  • sem_destroy()用于销毁一个信号量对象。

函数原型如下:

int sem_destroy(sem_t *sem)
  • sem_wait()尝试获取一个信号量,如果信号量值大于零,则将其减少并继续执行;否则,线程将被阻塞。

函数原型如下:

int sem_wait(sem_t *sem); //P()
  • sem_post():释放一个信号量,将其值增加,唤醒可能正在等待该信号量的线程。

函数原型如下:

int sem_post(sem_t *sem);//V()
  • sem_trywait():与 sem_wait() 类似,但是尝试获取信号量时不阻塞线程,而是立即返回。
  • sem_timedwait():与 sem_wait() 类似,但是可以设置超时时间,如果在超时时间内仍无法获取信号量,则返回错误。

以上两个函数了解即可.


基于环形队列的生产消费者模型

        这个相当于改变了交易场所,由阻塞队列变成了 环形队列.

下面是利用环形队列的几种策略:

  • 环形队列采用数组模拟,用模运算来模拟环状特性

  • 但是上面的设计有一个问题,假设head生产,tail消费;就是当head和tail重合的时候,我们不知道到底是head == tail还是tail == head, 即不知道此时环形队列为空还是为满。所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态,这个原理大家可以去网上查找环形队列的相关知识,这个置空位恰好将head和tail隔开。

  • 但是现在有了信号量这个计数器,所以也能轻松地实现 线程间利用环形队列同步的过程。 

整体代码设计如下:

        首先用类设计一个环形队列RingQueue,并封装一些接口push()和pop(),成员变量为一个vector数组(用数组模拟实现环形队列)、int num_ 用来表示环形队列的大小,c_step表示消费者的下标,p_step表示生产者的下标,然后有两个信号量space_sem_data_sem_,分别表示空间资源信号量和数据资源信号量。一开始的时候没有数据,所有空间都可使用,所以我们将空间资源信号量space_sem_设置为环形队列的长度ndata_sem_设置为0,表示没有数据。

        信号量的数据类型为sem_t,但是为了方便,我对信号量进行了一个封装,类Sem,里面包含了信号量的初始化,p()和v()操作等,然后上面两个信号量的类型就直接使用Sem.

然后在RingQueue类中,两个接口push和pop的实现逻辑如下:

  • push():这是生产者所使用的,生产者关注的是空间资源,如果有空间就生产,没有就停止。 生产后空间资源信号量space_sem_-1,但是数据资源信号量data_sem_+1,然后每次就在对应位置上写入相应的数据即可,记得模上数组的长度,因为逻辑结构是一个环形队列。
  • pop():这是消费者所使用的,消费者关注的是数据资源,有数据就消费,没数据就不能消费。消费后数据资源信号量data_sem_-1,但是空间资源信号量space_sem+1,同样地将对应位置的数据取出即可。

所以环形队列RingQueue类和Sem类的代码如下:

Ringqueue.hpp类

#pragma once
#include<iostream>
#include<pthread.h>
#include<vector>
#include "Sem.hpp"
using namespace std;const int g_default_num = 5;template<class T>
class RingQueue
{
public://对环形队列进行初始化RingQueue(int default_num = g_default_num):ring_queue_(g_default_num),num_(g_default_num),c_step(0),p_step(0),space_sem_(default_num),data_sem_(0){}~RingQueue(){}//生产者:关注空间资源void push(const T& in){space_sem_.p();ring_queue_[p_step++] = in;p_step %= num_;data_sem_.v();}//消费者:关注数据资源void pop(T* out){data_sem_.p();*out = ring_queue_[c_step++];c_step %= num_;space_sem_.v();}private:vector<T> ring_queue_;int num_;int c_step;//消费者下标int p_step;//生产者下标Sem space_sem_;Sem data_sem_;
};

Sem.hpp类

#pragma once
#include "ringQueue.hpp"
#include <semaphore.h>class Sem
{
public:Sem(int val){sem_init(&sem_,0,val);}void p(){sem_wait(&sem_);}void v(){sem_post(&sem_);}~Sem(){sem_destroy(&sem_);}
private:sem_t sem_;
};

然后我们对代码进行测试,测试代码如下,和上一节的测试代码几乎一样:

#include "ringQueue.hpp"
#include<sys/types.h>
#include<unistd.h>
#include <time.h>
using namespace std;
void* consumer(void* args)
{RingQueue<int>* rq = (RingQueue<int>*)args;while(true){int x;//1.从环形队列中拿取数据rq->pop(&x);//2.进行一定的处理cout << "消费: " << x << endl; }
}
void* producter(void* args)
{RingQueue<int>* rq = (RingQueue<int>*)args;while ((true)){//1.构建数据或任务对象 -- 一般可以从外部来,不要忽略时间消耗问题int x = rand() % 100 + 1;cout << "生产: " << x << endl; //2.推送到环形队列中rq->push(x);//完成生产的过程// sleep(1);}}int main()
{srand((unsigned int)time(nullptr) ^ getpid() ^ 12366 );RingQueue<int>* rq = new RingQueue<int>();pthread_t c,p;// rq->debug();pthread_create(&c,nullptr,consumer,(void*)rq);pthread_create(&p,nullptr,producter,(void*)rq);pthread_join(c,nullptr);pthread_join(p,nullptr);return 0;
}

代码也成功的执行了:

 


        上面是单线程,即单生产者,单消费者。

        我们也改成多线程并发执行的,这也是生产消费者模型的意义所在。

        当多线程并发执行时,如果两个线程 同时访问临界资源可能出错,所以需要在临界资源前后加上锁,使得只能有一个线程可以访问临界资源。

        但是这样和单线程有什么区别啊,都是单线程访问,多线程的意义在哪里?

        首先不要狭隘的认为,把任务或数据放在交易场所就是生产和消费了。将数据或任务拿到之后的处理,才是最耗费时间的,虽然拿的时候是加锁一个个拿的,但是处理的时候,却是一起处理的所以生产消费者模型主要意义体现在可以并发的处理任务

  • 生产的本质:私有的任务 -> 公共空间中
  • 消费的本质:公共空间中 -> 私有的

信号量本质是一把计数器 那计数器的意义是什么?

        可以不用进入临界区,就可以得知资源的情况,甚至可以减少临界区内部的判断。

申请锁 -> 判断临界资源和访问 -> 释放锁 ---> 本质我们并不清楚临界资源的情况,信号量要提前预设资源的情况,而且在pv变化中,我们在外部就可以知道临界资源的情况.

        所以我们在RingQueue类中,加入两个锁,分别为生产者和消费者:

 主函数中,创建多个线程:

 

 运行后,可以发现不同的线程生产和消费任务了。

这便是本章的全部内容了,主要讲述了POSIX信号量,即基于环形队列的生产消费者模型的一个实现。

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

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

相关文章

windows结束explorer进程后桌面白屏解决

背景 结束进程时一不小心一起删掉explorer.exe &#xff0c;这个文件结束桌面就一片白 &#xff0c; 解决&#xff1a; 不要关机&#xff0c;同时按键盘上ctrlshiftesc ,重新进入任务管理器&#xff0c;接着点“进程”选项&#xff0c;按左上角文件选项&#xff0c;进入下拉菜单…

备份或同步数据?跨国大文件传输的不同需求与解决方案

信息化时代的到来&#xff0c;使得许多个人、组织、企业在日常生活中都需要对数据进行备份或同步。但不同的应用场景和需求&#xff0c;也需要不同的备份和同步方式。而在跨国大文件传输方面&#xff0c;更是需要根据不同需求选择合适的传输方案。下面将分别介绍备份与同步数据…

BeanFactoryApplicationContext之间的关系

1**.BeanFactory与ApplicationContext之间的关系** &#xff08;1&#xff09;从继承关系上来看&#xff1a; ​ BeanFactory它是ApplicationContext 的父接口 &#xff08;2&#xff09;从功能上来看&#xff1a; ​ BeanFactory才是spring中的核心容器&#xff0c;而Appli…

【数学建模】-- 数学规划模型

概述&#xff1a; 什么是数学规划&#xff1f; 数学建模中的数学规划是指利用数学方法和技巧对问题进行数学建模&#xff0c;并通过数学规划模型求解最优解的过程。数学规划是一种数学优化方法&#xff0c;旨在找到使目标函数达到最大值或最小值的变量取值&#xff0c;同时满足…

VGG简单学习

VGG简单学习 简单介绍 在AlexNet网络的基础上&#xff0c;为了设计深层神经网络&#xff0c;牛津大学设计了VGG网络,采用块的设计理念&#xff0c;将AlexNet中多个重复的卷积层和池化层组成一个块 论文中&#xff0c;使用3x3卷积核&#xff0c;padding1的卷积层 和带有2x2的汇…

WebMagic - 创意前端项目集合(点击链接可在电脑上查看效果)

WebMagic - 创意前端项目集合 欢迎来到 WebMagic 仓库&#xff01;这里汇集了一系列令人惊叹的前端项目&#xff0c;涵盖了HTML5、CSS3和JS等多项技术。无论你是前端开发者、设计师&#xff0c;还是对创意互动内容感兴趣的人&#xff0c;这个仓库都将为你带来无尽的惊喜。 每…

LangChain手记 Chains

整理并翻译自DeepLearning.AILangChain的官方课程&#xff1a;Chains&#xff08;源代码可见&#xff09; Chains 直译链&#xff0c;表达的意思更像是对话链&#xff0c;对话链的背后是思维链 LLM Chain&#xff08;LLM链&#xff09; 首先介绍了一个最简单的例子&#xff0c…

代码审计-java项目-组件漏洞审计

代码审计必备知识点&#xff1a; 1、代码审计开始前准备&#xff1a; 环境搭建使用&#xff0c;工具插件安装使用&#xff0c;掌握各种漏洞原理及利用,代码开发类知识点。 2、代码审计前信息收集&#xff1a; 审计目标的程序名&#xff0c;版本&#xff0c;当前环境(系统,中间件…

图数据库_Neo4j和SpringBoot整合使用_实战创建明星关系图谱---Neo4j图数据库工作笔记0010

然后我们再来看一下这个明星关系图谱 可以看到这里 这个是原来的startRelation 我们可以写CQL去查询对应的关系 可以看到,首先查询出来以后,然后就可以去创建 我们可以把写的创建明星关系的CQL,拿到 springboot中去执行 可以看到,这里我们先写一个StarRelationRepository,然…

Java二分法查找

二分法&#xff1a;首先需要一个由小到大排序好的数组&#xff0c;先找到其中间值&#xff0c;然后进行比较如果比较中间值大的话则向前找。如果比要找的小&#xff0c;则向后找。 代码实现&#xff1a; //定义查询方法 public static int searchTarget(int[] nums, int targ…

wireshark界面内容含义

网络分析工具——WireShark的使用&#xff08;超详细&#xff09;_世间繁华梦一出的博客-CSDN博客 wireshark抓包数据&#xff1a;理解与分析_wireshark里面length_ 佚名的博客-CSDN博客

【图书推荐 | 测试】—《测试设计思想》

前言 随着科技的不断发展&#xff0c;互联网的不断进步&#xff0c;日益出现了一种趋势&#xff1a;测试设计将成为一种跨领域的综合性工作&#xff0c;测试者将成为一种跨领域的通用型人才。由此清华大学出版社推出了一本名为《测试设计思想》的书籍&#xff0c;由知名专家周…

ios swift5 collectionView 瀑布流(两列)

文章目录 1.瀑布流1.1 demo地址1.2 记得把部署的最低版本由8改成11,13甚至更高。不然编译会报错 2.动态计算图片和文字的高度 1.瀑布流 1.1 demo地址 CollectionViewWaterfallLayout - github 1.2 记得把部署的最低版本由8改成11,13甚至更高。不然编译会报错 2.动态计算图片和…

产业园区数字孪生3d可视化全景展示方案

随着数字经济的发展&#xff0c;数字技术给企业发展带来了机遇的同时&#xff0c;也为企业管理带来挑战。比如园区运维&#xff0c;不仅体量大&#xff0c;复杂的运维管理系统&#xff0c;落地难度也较高。那么如何通过数字化手段重塑园区运营&#xff0c;打通园区各业务数据孤…

SQLyog中导入CSV文件入库到MySQL中

1.在数据库中新建一个表&#xff0c;设置列名&#xff08;与待导入文件一致&#xff09;&#xff0c;字段可以多出几个都可以 2.右键表名&#xff0c;导入- - >导入使用本地加载的CSV数据 选择使用加载本地CVS数据 3.指定好转义字符&#xff0c;将终止设置为,号(英文状态下…

idea常见错误大全之:解决全局搜索失效+搜索条件失效(条件为空)+F8失灵

问题一&#xff1a;全局搜索快捷键ctrlshiftf 突然失灵了&#xff0c;键盘敲烂了 都没反应&#xff0c;这是为什么呢&#xff1f; 肯定不是idea本身的原因&#xff0c;那么就是其它外在因素影响到了idea的快捷键&#xff0c;那么其它的快捷键为什么没失效呢&#xff0c;原因只有…

服务器扩展未生效

服务器扩容未生效 在阿里云付费扩容后&#xff0c;在服务器里面看未生效。 阿里云->实例与镜像->实例->选择实例->云盘->扩容进入linux服务器查看&#xff1a; df -h vda1扩容未生效。原40g->扩容后100g 解决方法&#xff1a; 1、安装growpart yum inst…

广州华锐互动:奶牛难产原因及救治VR仿真实训系统

奶牛难产是一种常见的疾病&#xff0c;对奶牛的健康和生产造成很大的影响。为了解决这一问题&#xff0c;许多奶牛养殖场开始采用VR仿真技术来培训奶牛兽医&#xff0c;帮助学生更好地理解奶牛养殖的实际过程&#xff0c;提高他们的实践能力的教学方式。 VR技术开发公司广州华锐…

【算法】双指针划分思想妙解移动零

Problem: 283. 移动零 文章目录 思路算法图解分析复杂度Code 思路 首先我们来讲一下本题的思路 本题主要可以归到【数组划分/数组分块】这一类的题型。我们将一个数组中的所有元素划分为两段区间&#xff0c;左侧是非零元素&#xff0c;右侧是零元素 那解决这一类的题我们首先想…

掌握指针进阶:一篇带你玩转函数指针、函数指针数组及指向函数指针数组的指针!!

&#x1f341;博客主页&#xff1a;江池俊的博客 &#x1f4ab;收录专栏&#xff1a;C语言进阶之路 &#x1f4a1;代码仓库&#xff1a;江池俊的代码仓库 &#x1f3aa;我的社区&#xff1a;GeekHub &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐ 文章目录 一…