Linux之信号量

目录

信号量

信号量相关接口

创建信号量

初始化信号量 

等待信号量,P操作

发布信号量,V操作 

销毁信号量

基于信号量的环形队列下的生产者和消费者模型 

环形队列

代码实现


上期我们学习了线程同步的概念,掌握了基于阻塞队列的生产者和消费者模型。基于阻塞队列的生产者和消费者模型,三种关系,两个角色,一个场所,现在我们要关注的就是这一个场所,在此模型中,我们把阻塞队列称为临界资源,但是基于此模型,有且仅有这一个临界资源,也就是说临界资源的数目只有这一个。但是很多场景下临界资源的数目并不只有一个,本期我们主要研究的就是临界资源不只有一个的场景下的生产者和消费者模型。

信号量

我们之前学习了临界资源的概念,临界资源其实就是可以被多个执行流访问的资源。上节课的生产者和消费者模型,只有超市这一个临界资源。还有一个场景,就是电影院这个场景,在电影中,电影院的座位可以被多个顾客使用,所以电影院的座位就是临界资源,且电影院的座位不单单只有一个,所以临界资源是有多个的。那么信号量是什么呢?

信号量用于描述临界资源的数目的大小,比如在电影院的模型下,信号量就可以表示座位的多少。 任何线程要访问临界资源,必须先申请信号量,访问完临界资源,必须释放信号量。申请信号量我们称为P操作,释放信号量我们称为V操作。

通过伪代码为大家讲述p操作和v操作。 

当然并不是所有临界资源都可以用信号量来表示其数目的多少。当一个临界资源可以被细分时,我们才可以用临界资源来表示临界资源的数目的多少,当一个临界资源被分成了多个小的临界资源时,此时就可以实现多个执行流共同访问临界资源,从而实现,多个执行流的并发,从而提高代码的执行效率。

信号量相关接口

信号量的接口与互斥锁接口和条件变量接口类似。

创建信号量

sem_t  sem;       //创建信号量 

初始化信号量 

int sem_init(sem_t *sem, int pshared, unsigned int value);          //初始化信号量

sem为创建的信号量的地址;pshared,0表示线程间共享,非0表示进程间共享;value表示信号量的初始值。

等待信号量,P操作

int sem_wait(sem_t *sem);           //P()

等待信号量,表示申请信号量,要使用资源。将信号量减1。

发布信号量,V操作 

sem_post(sem_t *sem);          //V()

发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。

销毁信号量

int sem_destroy(sem_t *sem);           //销毁信号量  

基于信号量的环形队列下的生产者和消费者模型 

环形队列

上图为一个环形队列,有生产者和消费者两个角色,环形队列为一个大的临界资源,这个大的临界资源有被分成了多个小部分,为多份小的临界资源。 

代码实现

生产者往环形队列中生产数据,消费者从环形队列中消费数据。生产者每生产一个数据前进一格,当生产者和消费者相遇时,要么是环形队列为空,要么是环形队列中的数据已满。基于此,我们对基于环形队列的生产者和消费者模型设立两个规则。

规则一:生产者不能把消费者逃一圈,因为一旦套了一圈,势必会造成相遇时,生产者和消费者所处的环形队列的那一块空间中数据的覆盖,造成数据丢失。

规则二:因为刚开始环形队列是为空的,所以刚开始一定是生产者先生产,然后再是消费者再进行消费,正是基于此,往后消费者的位置一定是不能超过生产者的。

生产者看重的是环形队列中的空白位置的数目,而消费者看重的是环形队列中数据的数目。所以创建两个信号量,一个信号量描述环形队列中空位置的数目,一个信号量描述环形队列中数据的数目。

代码实现如下。

 RingQueue.hpp

#include <iostream>
#include <vector>
#include <semaphore.h>namespace yjd
{const int DefaultCapacity = 10;template <class T>class RingQueue{public:RingQueue(const int &capacity = DefaultCapacity): _v(capacity){_capacity = capacity;sem_init(&_blank_sem, 0, 10);sem_init(&_data_sem, 0, 0);_c_step = _p_step = 0;}~RingQueue(){sem_destroy(&_blank_sem);sem_destroy(&_data_sem);}void push(T &data){sem_wait(&_blank_sem);_v[_p_step] = data;sem_post(&_data_sem);_p_step++;_p_step % _capacity;}void pop(T *data){sem_wait(&_data_sem);*data = _v[_c_step];sem_post(&_blank_sem);_c_step++;_c_step%_capacity;}private:std::vector<T> _v;int _capacity;// 描述空位置的数目sem_t _blank_sem;// 描述数据的数目sem_t _data_sem;int _p_step;int _c_step;};
}

整个代码的逻辑为,生产者先生产数据,然后消费者消费数据。生产者要生产数据,先申请一个空位置信号量,空位置信号量减1,然后生产数据,生产完数据之后,数据信号量加1;消费者消费数据时,先申请数据信号量,数据信号量减1,消费完数据之后,多了一个空位置,空位置信号量加1。

 RingCP.cc

#include "RingQueue.hpp"
#include <pthread.h>
#include <unistd.h>
#include <time.h>using namespace yjd;void *producter(void *args)
{RingQueue<int> *rq = (RingQueue<int> *)args;while (true){int data = rand() % 20 + 1;rq->push(data);std::cout << "生产者生产数据 " << data << std::endl;}
}void *consumer(void *args)
{RingQueue<int> *rq = (RingQueue<int> *)args;while (true){int data = 0;rq->pop(&data);std::cout << "消费者消费数据 " << data << std::endl;sleep(1);}
}int main()
{pthread_t c;pthread_t p;RingQueue<int> *rq = new RingQueue<int>();srand((long long)time(nullptr));pthread_create(&c, nullptr, consumer, (void *)rq);pthread_create(&p, nullptr, producter, (void *)rq);pthread_join(c, nullptr);pthread_join(p, nullptr);return 0;
}

运行结果如下。

通过运行结果可知,我们通过使用信号量和唤醒队列,实现了生产和消费者的同步。  

以上便是本期信号量的相关知识点。

本期内容到此结束 ^_^

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

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

相关文章

【电子通识】PWM驱动让有刷直流电机恒流工作

电机的典型驱动方法包括电压驱动、电流驱动以及PWM驱动。本文将介绍采用PWM驱动方式的恒流工作。 首先介绍的是什么是PWM驱动的电机恒流工作&#xff0c;其次是PWM驱动电机恒流工作时电路的工作原理。 PWM驱动 当以恒定的电流驱动电机时&#xff0c;电机会怎样工作呢&#xff1…

Kafka 消费者专题

目录 消费者消费者组消费方式消费规则独立消费主题代码示例&#xff08;极简&#xff09;代码示例&#xff08;独立消费分区&#xff09; offset自动提交代码示例&#xff08;自动提交&#xff09;手动提交代码示例&#xff08;同步&#xff09;代码示例&#xff08;异步&#…

【游戏设计原理】47 - 超游戏思维

对于这条原理&#xff0c;我首先想到的是开放世界&#xff0c;或者探索性游戏&#xff0c;这是最能包容各类玩家的游戏类型。这类游戏定义了基本规则&#xff0c;玩家的可操作性很强。就像上图里的沙池一样&#xff0c;里面有滑梯&#xff0c;是规则性比较明确的&#xff0c;而…

奥迪TT MK1(初代奥迪TT、第一代奥迪TT)仪表盘故障/不精准/水温/剩余油量不准,如何修复、测试、复位?

故障现象 水温不准&#xff0c;冷启动就130℃汽油加满&#xff0c;指针依然在中间偏左的位置 如下图&#xff1a; 诊断过程 通过VAG KKL 409 USB OBD接口读取水温和油位数值正常&#xff0c;故判断是仪表指针马达损坏或需要重置指针位置 维修步骤 推荐选择CH340&#xff08;老…

Nginx——服务器端集群搭建与扩展模块(五/五)

目录 1.Nginx实现服务器端集群搭建1.1.Nginx 与 Tomcat 部署1.1.1.环境准备 (Tomcat)1.1.2.环境准备 (Nginx) 1.2.Nginx实现动静分离1.2.1.概述1.2.2.需求分析1.2.3.动静分离实现步骤 1.3.Nginx 实现 Tomcat 集群搭建1.4.Nginx 高可用解决方案1.4.1.概述1.4.2.Keepalived 介绍1…

创建VUE脚手架

1.输入 npm create vuelatest2.创建完成

JavaWeb开发(六)XML介绍

1. XML介绍 1.1. 什么是XML &#xff08;1&#xff09;XML 指可扩展标记语言(EXtensible Markup Language)XML 是一种很像HTML的标记语言。   &#xff08;2&#xff09;XML 的设计宗旨是传输数据(目前主要是作为配置文件)&#xff0c;而不是显示数据。   &#xff08;3&a…

WebRtc02:WebRtc架构、目录结构、运行机制

整体架构 WebRtc主要分为三层&#xff1a; CAPI层&#xff1a;外层调用Session管理核心层&#xff1a;包括视频引擎、音频引擎、网络传输 可由使用者重写视频引擎&#xff1a;编解码器、视频缓存、视频增强音频引擎&#xff1a;编解码器、音频缓存、回音消除、降噪传输&#x…

【Qt】快速添加对应类所需的头文件包含

快速添加对应类所需的头文件包含 一&#xff0c;简介二&#xff0c;操作步骤 一&#xff0c;简介 本文介绍一下&#xff0c;如何快速添加对应类所需要包含的头文件&#xff0c;可以提高开发效率&#xff0c;供参考。 二&#xff0c;操作步骤 以QTime类为例&#xff1a; 选中…

WPF通过反射机制动态加载控件

Activator.CreateInstance 是 .NET 提供的一个静态方法&#xff0c;它属于 System 命名空间。此方法通过反射机制根据提供的类型信息。 写一个小demo演示一下 要求&#xff1a;在用户反馈界面点击建议或者评分按钮 弹出相应界面 编写MainWindow.xmal 主窗体 <Window x:C…

宽带、光猫、路由器、WiFi、光纤之间的关系

1、宽带&#xff08;Broadband&#xff09; 1.1 宽带的定义宽带指的是一种高速互联网接入技术&#xff0c;通常包括ADSL、光纤、4G/5G等不同类型的接入方式。宽带的关键特点是能够提供较高的数据传输速率&#xff0c;使得用户可以享受到稳定的上网体验。 1.2 宽带的作用宽带是…

Pytest钩子函数,测试框架动态切换测试环境

在软件测试中&#xff0c;测试环境的切换是个令人头疼的问题。不同环境的配置不同&#xff0c;如何高效切换测试环境成为许多测试开发人员关注的重点。你是否希望在运行测试用例时&#xff0c;能够动态选择测试环境&#xff0c;而不是繁琐地手动修改配置&#xff1f; Pytest 测…

印象笔记07——试一试PDF标注

印象笔记07——试一试PDF标注 [!CAUTION] 根据第六期&#xff0c;我再次查询了资料&#xff0c;印象笔记还是有一些可圈可点的功能的&#xff08;当然部分有平替&#xff09;&#xff0c;针对会员作用&#xff0c;开发使用场景虽然是逆向的&#xff0c;但我坚信这是一部分人的现…

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…

通过串口通信控制led灯的亮灭

初始化led灯的gpio接口控制灯的亮灭 初始化uart1串口 将gpio9和gpio10设置为复用模式进行串口通信 通过串口的输入输出函数实现串口通信控制led灯的亮灭

计算机xinput1_4.dll丢失怎么修复?

电脑运行时常见问题及修复指南 作为软件开发从业者&#xff0c;深知电脑在日常使用中难免会遇到各种问题&#xff0c;如文件丢失、文件损坏和系统报错等。这些问题不仅影响工作效率&#xff0c;还可能带来数据丢失的风险。本文将详细介绍一些常见问题及其解决办法&#xff0c;…

DeepSeek V3“报错家门”:我是ChatGPT

搜 &#xff1a;海讯无双Ai 要说这两天大模型圈的顶流话题&#xff0c;那绝对是非DeepSeek V3莫属了。 不过在网友们纷纷测试之际&#xff0c;有个bug也成了热议的焦点—— 只是少了一个问号&#xff0c;DeepSeek V3竟然称自己是ChatGPT。 甚至让它讲个笑话&#xff0c;生成…

C++:范围for

范围for&#xff08;range-based for&#xff09;是C的一种循环结构&#xff0c; 是在 C11 这个标准中引入的&#xff0c;这种类型的for循环使得遍历数组、容器中的元素更加简便和直观。 一、范围for语法 for ( 类型 变量名 : 数组名 ) 语句 //多条语句需要加⼤括号 示例&#…

C++基础概念复习

前言 本篇文章作基础复习用&#xff0c;主要是在C学习中遇到的概念总结&#xff0c;后续会继续补充。如有不足&#xff0c;请前辈指出&#xff0c;万分感谢。 1、什么是封装&#xff0c;有何优点&#xff0c;在C中如何体现封装这一特性&#xff1f; 封装是面向对象编程&…

前端工程化之手搓webpack5 --【elpis全栈项目】

前端工程化之手搓webpack5 --【elpis全栈项目】 导读 基本流程&#xff1a;输入 – 编译 – 输出 #mermaid-svg-V8Gi7RFNikCuEhax {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-V8Gi7RFNikCuEhax .error-icon{fil…