当前位置: 首页 > news >正文

【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信号量,即基于环形队列的生产消费者模型的一个实现。

相关文章:

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

目录 写在前面的话 什么是POSIX信号量 POSIX信号量的使用 基于环形队列的生产消费者模型 写在前面的话 本文章主要先介绍POSIX信号量&#xff0c;以及一些接口的使用&#xff0c;然后再编码设计一个基于环形队列的生产消费者模型来使用这些接口。 讲解POSIX信号量时&#x…...

Rust之编写自动化测试

1、测试函数的构成&#xff1a; 在最简单的情形下,Rust中的测试就是一个标注有test属性的函数。属性 (attribute)是一种用于修饰Rust代码的元数据。只需要将#[test]添加到关键字fn的上一行便可以将函数转变为测试函数。当测试编写完成后,我们可以使用cargo test命令来运行测试…...

【网络】网络层——IP协议

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 网络层中&#xff0c;IP协议首部和有效载荷组成的完整数据称为数据报。 IP协议 &#x1f349;TCP和IP的…...

动力电池系统介绍(十三)——高压互锁(HVIL)

动力电池系统介绍&#xff08;十三&#xff09; 一、高压互锁梗概1.1 高压互锁原理1.1 高压互锁内部结构1.2 高压互锁分类1.3 高压互锁原则 二、高压互锁常见故障2.1 高压互锁开关失效2.2 端子退针导致开路2.3 互锁端子对地短路2.4 动力电池内部故障 三、高压互锁故障排查 一、…...

C# 一种求平方根的方法 立方根也可以 极大 极小都可以

不知道研究这些干啥&#xff0c;纯纯的浪费时间。。。 public static double TQSquare(double number){Random random1 new Random(DateTime.Now.Millisecond);double x1 0, resultX1 0, diff 9999999999, diffTemporary 0;for (int i 0; i < 654321; i){if (random1…...

爬虫逆向实战(十二)--某交易所登录

一、数据接口分析 主页地址&#xff1a;某交易所 1、抓包 通过抓包可以发现登录是通过表单提交的 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块&#xff0c;可以发现有两个加密参数password和execution 请求头是否加密&#xff1f; 无响应是…...

【C++入门到精通】C++入门 —— list (STL)

阅读导航 前言一、list简介1.概念2.特点 二、list的使用1.list的构造2.常见的操作⭕std::list类型的增、删、查、改 三、list与vector的对比温馨提示 前言 文章绑定了VS平台下std::list的源码&#xff0c;大家可以下载了解一下&#x1f60d; 前面我们讲了C语言的基础知识&…...

SOLIDWORKS有限元分析

SOLIDWORKS是一款广泛使用的三维计算机辅助设计软件&#xff0c;同时它还具有强大的有限元分析功能。有限元分析是一种工程分析方法&#xff0c;它将复杂的实体分解成许多小的有限元素&#xff0c;以便对其进行数学建模和分析。SOLIDWORKS的有限元分析功能可以帮助工程师预测和…...

Kotlin Flow 冷流

协程&#xff1a;Flow 1、Flow是什么&#xff1f; 处理异步事件流可取消&#xff1a;通过取消协程取消Flow组合操作符&#xff1a;复杂逻辑处理缓冲和背压&#xff1a;发送和接收时用不同速度处理&#xff0c;实现流量控制、避免数据丢失 2、传统事件处理方案&#xff1a;同…...

Android Socket使用TCP协议实现手机投屏

本节主要通过实战来了解Socket在TCP/IP协议中充当的是一个什么角色&#xff0c;有什么作用。通过Socket使用TCP协议实现局域网内手机A充当服务端&#xff0c;手机B充当客户端&#xff0c;手机B连接手机A&#xff0c;手机A获取屏幕数据转化为Bitmap&#xff0c;通过Socket传递个…...

【云原生,k8s】Helm应用包管理器介绍

目录 一、为什么需要Helm&#xff1f; &#xff08;一&#xff09;Helm介绍 &#xff08;二&#xff09;Helm有3个重要概念&#xff1a; &#xff08;三&#xff09;Helm特点 二、Helm V3变化 &#xff08;一&#xff09;架构变化 &#xff08;二&#xff09;自动创建名…...

两个内网之间的linux服务器如何互相登录?快解析内网穿透

如果两个内网之间的linux服务器需要互相登录&#xff0c;或需要互相访问内网某个端口&#xff0c;担忧没有公网IP&#xff0c;可以使用的方法有 ngrok, 但并不方便&#xff0c;我们只需两条 SSH 命令即可。 SSH 内网端口转发实战SSH 内网端口转发实战 先给出本文主角&…...

sql server 存储过程 set ansi_nulls set quoted_identifier,out 、output

SQL-92 标准要求在对空值(NULL) 进行等于 () 或不等于 (<>) 比较时取值为 FALSE。 当 SET ANSI_NULLS 为 ON 时&#xff0c;即使 column_name 中包含空值&#xff0c;使用 WHERE column_name NULL 的 SELECT 语句仍返回零行。即使 column_name 中包含非空值&#xff0c…...

1046:判断一个数能否同时被3和5整除

【题目描述】 判断一个数n 能否同时被3和5整除&#xff0c;如果能同时被3和5整除输出YES&#xff0c;否则输出NO。 【输入】 输入一行&#xff0c;包含一个整数n。&#xff08; -1,000,000 < n < 1,000,000&#xff09; 【输出】 输出一行&#xff0c;如果能同时被3…...

优漫动游零基础如何学习好UI设计

智能时代的来临&#xff0c;很多企业都越来越注重用户体验这一块&#xff0c;想要有一个吸引用户的好页面&#xff0c;UI设计师岗位不可或缺&#xff0c;如今越来越多的人想要学习UI设计技术&#xff0c;那么对于零基础小白如何学习好UI设计呢? 零基础小白如何学习好UI设计…...

Android岗位技能实训室建设方案

一 、系统概述 Android岗位技能作为新一代信息技术的重点和促进信息消费的核心产业&#xff0c;已成为我国转变信息服务业的发展新热点&#xff1a;成为信息通信领域发展最快、市场潜力最大的业务领域。互联网尤其是移动互联网&#xff0c;以其巨大的信息交换能力和快速渗透能力…...

Mysql系列:Mysql5.7编译安装--系统环境:Centos7 / CentOS9 Stream

Mysql系列&#xff1a;Mysql5.7编译安装 系统环境&#xff1a;Centos7 / CentOS9 Stream 1&#xff1a;下载mysql源码包 https://dev.mysql.com/downloads/mysql/5.7.htmldownloads 选择MySQL Community Server>source_code>Generic Linux (Architecture Independent)…...

Docker容器与虚拟化技术:Dockerfile部署LNMP

目录 一、理论 1.LNMP架构 2.背景 3.Dockerfile部署LNMP 3.构建Nginx镜像 4.构建MySQL容器 5.构建PHP镜像 6.启动 wordpress 服务 二、实验 1.环境准备 2.构建Nginx镜像 3.构建MySQL容器 4.构建PHP镜像 5.启动 wordpress 服务 三、问题 1.构建nginx镜像报错 …...

elementUI date-picker 日期格式转为 2023/08/08格式

<el-form-item label"基线日期:" prop"baselineDate"><el-date-pickertype"date"v-model"form.baselineDate"placeholder"选择日期"format"yyyy/MM/dd"change"(date, type) > changeTime(date, …...

生成式 AI 在泛娱乐行业的应用场景实践 – 助力风格化视频内容创作

感谢大家阅读《生成式 AI 行业解决方案指南》系列博客&#xff0c;全系列分为 4 篇&#xff0c;将为大家系统地介绍生成式 AI 解决方案指南及其在电商、游戏、泛娱乐行业中的典型场景及应用实践。目录如下&#xff1a; 《生成式 AI 行业解决方案指南与部署指南》《生成式 AI 在…...

开放标准如何重塑多媒体设备开发:从碎片化到模块化

1. 项目概述&#xff1a;为什么我们需要一个“开放标准”&#xff1f;如果你在消费电子、汽车座舱或者智能家居领域待过几年&#xff0c;一定会对“多媒体设备”这个词又爱又恨。爱的是&#xff0c;它代表了用户体验的核心——那块屏幕、那套音响、那个能看视频能听歌的交互界面…...

QRazyBox终极指南:5步快速修复损坏的二维码

QRazyBox终极指南&#xff1a;5步快速修复损坏的二维码 【免费下载链接】qrazybox QR Code Analysis and Recovery Toolkit 项目地址: https://gitcode.com/gh_mirrors/qr/qrazybox 你是否曾经遇到过无法扫描的二维码&#xff1f;那些因打印模糊、屏幕损坏或污渍覆盖而失…...

AI报告审核正在提升阻燃材料检测可信度:IACheck如何减少PSU阻燃等级报告里的合规风险

做高性能工程塑料检测的人都知道&#xff0c;PSU材料的阻燃等级测试&#xff0c;看起来只是一个等级判定&#xff0c;但真正进入报告审核阶段以后&#xff0c;往往比实验本身更容易出问题。因为PSU&#xff0c;也就是聚砜材料&#xff0c;常用于电子电气、轨道交通、医疗器械以…...

聊天机器人技能并行化框架设计与实现:提升响应效率的异步编程实践

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目&#xff0c;叫mvanhorn/clawdbot-skill-parallel。乍一看这个仓库名&#xff0c;又是“clawdbot”又是“skill-parallel”&#xff0c;感觉像是某种机器人或自动化工具。没错&#xff0c;这正是它的核心。简单来说&…...

模块三-数据清洗与预处理——15. 异常值检测与处理

15. 异常值检测与处理 1. 概述 异常值&#xff08;Outlier&#xff09;是指与其他观测值显著不同的数据点。它们可能来自测量错误、数据录入错误&#xff0c;也可能是真实的极端情况&#xff08;如高收入人群&#xff09;。正确识别和处理异常值对数据分析至关重要。 import pa…...

如何快速集成DatePicker到你的Android项目

如何快速集成DatePicker到你的Android项目 【免费下载链接】DatePicker Useful and powerful date picker for android 项目地址: https://gitcode.com/gh_mirrors/da/DatePicker DatePicker是一款功能强大且易于使用的Android日期选择器&#xff0c;支持单选和多选模式…...

从零构建现代Web音乐应用:技术选型、音频引擎与全栈实践

1. 项目概述与核心价值最近在GitHub上看到一个挺有意思的项目&#xff0c;叫chemistwang/music-app。光看名字&#xff0c;你可能会觉得这又是一个“音乐播放器”&#xff0c;市面上类似的轮子已经多如牛毛了。但作为一个在前后端领域摸爬滚打多年的开发者&#xff0c;我习惯性…...

电子防盗扣用钢丝绳的抗拉强度与直径的关联规律

引言钢丝绳在现代工业领域中扮演着至关重要的角色。从大型机械设备到精细的电子防盗扣&#xff0c;钢丝绳凭借其独特的性能&#xff0c;保障着各类设备的稳定运行。在电子防盗扣的应用场景中&#xff0c;钢丝绳的抗拉强度直接关系到防盗扣的可靠性和安全性&#xff0c;而其直径…...

云代理商:Hermes Agent如何通过技能沉淀降低长期算力消耗

在 AI 智能体规模化落地的今天&#xff0c;算力成本高、重复推理多、长期运行效率衰减&#xff0c;已成为企业和开发者的核心痛点。传统 AI 智能体每处理一次相似任务&#xff0c;都要从零开始推理、反复调用工具&#xff0c;大量算力浪费在重复劳动中&#xff0c;长期使用成本…...

科研人员实用:OpenClaw批量下载文献、整理参考文献格式,自动生成论文引用列表

科研利器&#xff1a;OpenClaw——自动化文献下载、格式整理与引用列表生成实战指南摘要 在科研工作中&#xff0c;文献的收集、管理与引用是耗时耗力的关键环节。面对海量的学术资源&#xff0c;如何高效地批量下载所需文献、规范整理参考文献格式、并快速生成符合要求的论文引…...