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

《Linux从练气到飞升》No.30 深入理解 POSIX 信号量与生产消费模型

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux
菜鸟刷题集

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!

文章目录

    • 前言
    • 1 POSIX信号量相关概念
    • 2 POSIX信号量相关函数
    • 3 基于环形队列的生产消费模型

前言

在多线程编程领域,理解 POSIX 信号量的概念和相关函数是至关重要的。POSIX 信号量作为一种重要的同步原语,可以帮助我们在多线程环境中实现线程之间的协调与同步,从而确保数据的一致性和避免竞争条件的发生。

本篇博客旨在深入探讨 POSIX 信号量的基本概念和相关函数,帮助读者全面理解这一关键的并发编程工具。通过本文的学习,读者将能够掌握如何灵活地运用 POSIX 信号量来构建并发程序,提高程序的性能和可靠性。让我们一起深入探索 POSIX 信号量的奥秘,为多线程编程的世界增添新的智慧与力量。

1 POSIX信号量相关概念

POSIX信号量是什么?

信号量的本质是一个计数器,是用来描述临界资源有效的计数器

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
当多个线程想要获取信号量的时候,都会对信号量当中的资源计数器进行减一操作。
如果初始化信号量的资源计数器的值为1表示当前只有一个资源,这就意味着只有一个线程在同一时刻可以获取到信号量。
如果想要实现线程同步,初始化信号量的资源计数器的值就不必为1了,它可以根据需要设置

  • 如果大于0则表示还有多少资源可以使用
  • 等于0则表示没有资源可以使用
  • 小于0则表示有多少线程在等待资源。

2 POSIX信号量相关函数

  1. 信号量初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:sem_t: 信号量的类型sem: 传入待要初始化的信号量pshared: 0 表示线程间共享,非0表示进程间共享value:信号量初始值
  1. 信号量销毁
int sem_destroy(sem_t *sem);
参数:sem:待销毁的信号量
  1. 信号量等待
功能:等待信号量,会将信号量的值减1int sem_wait(sem_t *sem); //P()
  1. 信号量发布
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1int sem_post(sem_t *sem);//V()

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

  • 上一个生产者-消费者的例子是基于queue的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序(POSIX信号量)。

image.png

  • 环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态

image.png
但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程
实现代码如下:
RingQueue.cc

#pragma#include<iostream>
#include<unistd.h>
#include<vector>
#include<semaphore.h>
#include<stdlib.h>#define NUM 10class RingQueue
{
private:std::vector<int> v;int _cap;//容量sem_t sem_product;//生产者sem_t sem_consume;//消费者int p_index;//生产者索引int c_index;//消费者索引public:RingQueue(int cap=NUM):_cap(cap),v(cap){sem_init(&sem_product,0,cap);sem_init(&sem_consume,0,0);p_index = 0;c_index = 0;}~RingQueue(){sem_destroy(&sem_product);sem_destroy(&sem_consume);}void put(const int&in){sem_wait(&sem_product);v[p_index] = in;p_index++;p_index = p_index%NUM;sem_post(&sem_consume);}void get(int &out){sem_wait(&sem_consume);out = v[c_index];c_index++;c_index = c_index%NUM;sem_post(&sem_product);}
};

main.cc

#include"RingQueue.cc"
using namespace std;void* Consumer(void* arg){RingQueue *bq = (RingQueue*)arg;int data;while(1){bq->get(data);cout<<"I am "<<pthread_self()<<" is consumer : "<<data<<endl;}
}void* Product(void* arg){RingQueue* bq = (RingQueue*)arg;srand((unsigned int)time(NULL));while(1){int data = rand()%100;bq->put(data);cout<<"I am "<<pthread_self()<<" is product "<<data<<endl;sleep(1);}
}int main()
{RingQueue* pq = new RingQueue();pthread_t c;pthread_t p;pthread_create(&c,NULL,Consumer,(void*)pq);pthread_create(&p,NULL,Product,(void*)pq);pthread_join(c,NULL);pthread_join(p,NULL);return 0;
}

makefile

main:main.ccg++ -o $@ $^ -lpthread
.PHONY:
clean:rm -f main

结果:
可以观察到生产一个消费一个
image.png

相关文章:

《Linux从练气到飞升》No.30 深入理解 POSIX 信号量与生产消费模型

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…...

高防IP可以抵御哪些恶意攻击

高防IP协议可以隐藏用户的站点&#xff0c;使得攻击者无法发现恶意攻击的目标网络资源&#xff0c;从而提高了源站的安全性。能够有效抵御常见的恶意攻击类型ICMPFlood、UDPFlood、 TCPFlood、SYNFlood、ACKFlood等&#xff0c;帮助游戏、金 融、电子商务、互联网、政企等行业抵…...

vivado产生报告阅读分析6-时序报告2

1、复查时序路径详情 单击“ OK ”运行报告命令后 &#xff0c; 将打开一个新窗口。这样您即可复查其中内容。在其中可查看执行选定的每种类型 (min/max/min_max ) 的分析之后所报告的 N 条最差路径。 下图显示的“Report Timing ” &#xff08; 时序报告 &#xff09; 窗口…...

电脑怎么备份文件?简单几步,轻松备份!

电脑中存储着大量的个人和工作文件&#xff0c;包括照片、文档、音乐和视频等。但突发状况&#xff0c;如硬件故障、病毒感染或误删文件&#xff0c;可能会导致数据丢失。因此&#xff0c;备份文件至关重要。在本文中&#xff0c;我们将介绍三种电脑怎么备份文件的方法&#xf…...

获得不同干扰程度的模糊图像

同时对一共父级文件夹遍历。获得对应不同干扰程度的模糊图像 # This isimport cv2 import numpy as npdef reduce_resolution(image, factor):height, width, _ image.shape # 获取原始图像的宽度和高度new_width int(width / factor) # 计算新的宽度和高度new_height i…...

spring为什么要使用三级缓存来解决循环依赖

出现循环依赖的原因 AService依赖BService Service("aService") public class AService {AutowiredBService bService; } BService依赖AService Service("bService") public class BService {AutowiredAService aService; } 此时就出现了循环依赖 想…...

【自留地】前端 - uniapp - Vue - React - Flutter

uniapp uniapp自用速查表 - 我的常用组件 uniapp自用速查表 - 我的常用组件_uniapp static/customicons.css-CSDN博客文章浏览阅读1.8k次。uniapp项目登录退出、全局变量与状态、本地存储、Tabbar标签栏、顶部导航栏、下拉刷新、触底刷新、Ajax交互、内置组件样式修改、自定义…...

深度学习损失函数

Loss 是深度学习算法中重要的一部分&#xff0c;它的主要功能是评价网络预测的准确性和指导权重更新。合适 Loss 可以让网络收敛更快&#xff0c;预测更准。这个项目介绍了损失函数的基本概念以及7种常用损失函数的形式&#xff0c;性质&#xff0c;参数&#xff0c;使用场景及…...

百度智能云正式上线Python SDK版本并全面开源

文章目录 前言一、SDK的优势二、千帆SDK&#xff1a;快速落地LLM应用三、如何快速上手千帆SDK3.1、SDK快速启动3.2. SDK进阶指引 3.3. 通过Langchain接入千帆SDK4、开源社区 前言 百度智能云千帆大模型平台再次升级&#xff01;在原有API基础上&#xff0c;百度智能云正式上线…...

Elasticsearch的配置学习笔记

文/朱季谦 Elasticsearch是一个基于Lucene的搜索服务器。它提供一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口&#xff0c;Elasticsearch是用Java语言开发的。 关于Elasticsearch系列笔记&#xff0c;主要从Elasticsearch的配置、核心组件、架构设计、使…...

LeetCode(25)验证回文串【双指针】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 验证回文串 1.题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&…...

Android设计模式--工厂模式

一&#xff0c;定义 工厂模式与Android 设计模式--单例模式-CSDN博客&#xff0c;Android设计模式--Builder建造者模式-CSDN博客&#xff0c;Android设计模式--原型模式-CSDN博客 一样&#xff0c;都是创建型设计模式。 工厂模式就是定义一个用于创建对象的接口&#xff0c;让…...

EasyExcel入门使用教程

文章目录 简介一、工程创建&#x1f391;二、读操作&#x1f38a;二、写操作&#x1f384;总结 简介 数据导入导出意义 后台管理系统是管理、处理企业业务数据的重要工具&#xff0c;在这样的系统中&#xff0c;数据的导入和导出功能是非常重要的&#xff0c;其主要意义包括以下…...

Golang实现一个一维结构体,根据某个字段排序

package mainimport ("fmt""sort" )type Person struct {Name stringAge int }func main() {// 创建一个一维结构体切片people : []Person{{"Alice", 25},{"Bob", 30},{"Charlie", 20},{"David", 35},{"Eve…...

python语言实现背包问题动态规划

背包问题是一个经典的动态规划问题&#xff0c;实现方式如下&#xff1a; 假设有一个背包&#xff0c;容量为 W&#xff0c;有 n 个物品&#xff0c;每个物品有两个属性&#xff1a;体积 v 和价值 w。要求在不超过背包容量的情况下&#xff0c;选取一些物品放入背包&#xff0…...

将Python程序(.py)转换为Windows可执行文件(.exe)

python开发者向普通windows用户分享程序,要给程序加图形化的界面(传送门:这可能是最好玩的python GUI入门实例! http://www.jianshu.com/p/8abcf73adba3),并要将软件打包为可执行文件(.exe结尾),那如何将.py转为.exe ? 将.py转为.exe 第一步:安装pyinstaller(临时调用了国内豆…...

Oracle 查找非系统用户结合了10,11,12,19

oracle 12开始有了INHERITEDYES;字段来区分系统用户 select username from dba_users where INHERITEDYES; 对于12以下的版本&#xff0c;按created日期字段筛选会发现创建时间间隔比较大&#xff0c;好区分。 本人当前有个需求需要找出所有数据库的非系统用户&#xff0c;来…...

c++虚函数纯虚函数详解加代码解释

c虚函数纯虚函数详解加代码解释 一.概念&#xff1a;二.虚函数示例及解析&#xff1a;三.纯虚函数示例及解析&#xff1a;四.验证和实际使用及解析&#xff1a;1.子类没有对父类的函数重载&#xff0c;mian()函数调用&#xff0c;是直接返回父类的值2.子类对父类的函数重载&…...

kotlin retrofit

参考博客 【Android】【Kotlin】使用【Retrofit】基本使用 如何在kotlin中正确使用retrofit 将kotlin协程用于网络请求—完整实例&#xff0c;看这一篇就够了 Kotlin协程Retorfit网络请求框架封装...

Web 开发中 route 和 router 有什么区别?

什么是路由&#xff1f; 在 Web 开发中&#xff0c;会经常和路由打交道&#xff0c;可能有的同学并没有仔细思考过到底什么是路由。路由是根据用户请求的 URL 来确定返回给用户的内容或页面的技术&#xff0c;即将 HTTP 请求映射到相应的处理代码&#xff0c;使得用户能够通过…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

CMS内容管理系统的设计与实现:多站点模式的实现

在一套内容管理系统中&#xff0c;其实有很多站点&#xff0c;比如企业门户网站&#xff0c;产品手册&#xff0c;知识帮助手册等&#xff0c;因此会需要多个站点&#xff0c;甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...

C++ 变量和基本类型

1、变量的声明和定义 1.1、变量声明规定了变量的类型和名字。定义初次之外&#xff0c;还申请存储空间&#xff0c;也可能会为变量赋一个初始值。 如果想声明一个变量而非定义它&#xff0c;就在变量名前添加关键字extern&#xff0c;而且不要显式地初始化变量&#xff1a; e…...

C++ 使用 ffmpeg 解码 rtsp 流并获取每帧的YUV数据

一、简介 FFmpeg 是一个‌开源的多媒体处理框架‌&#xff0c;非常适用于处理音视频的录制、转换、流化和播放。 二、代码 示例代码使用工作线程读取rtsp视频流&#xff0c;自动重连&#xff0c;支持手动退出&#xff0c;解码并将二进制文件保存下来。 注意&#xff1a; 代…...