简单聊聊System V下的IPC + 内核是如何管理该IPC
文章目录
- 前言:
- 🎃消息队列:
- 1. **消息队列的基本概念**
- 2. **消息队列的特点**
- 3. **常见的消息队列操作(Linux IPC)**
- **1) `msgget`:创建或获取消息队列**
- **2) `msgsnd`:发送消息**
- **3) `msgrcv`:接收消息**
- **4) `msgctl`:控制消息队列**
- 4. **消息队列的基本操作示例(Linux C代码)**
- **消息发送示例**:
- **消息接收示例**:
- **删除消息队列**:
- 5. **消息队列的优缺点**
- **优点**:
- **缺点**:
- 6. **消息队列的应用场景**
- 🎃信号量:
- ❤️五个概念:
- ❤️对信号量的理解?
- 🍤对于不整体使用的资源:
- 🍚对于整体使用的资源:
- 🍗那我可不可以使用全局变量?
- OS是如何把共享内存、消息队列、信号量统一管理起来的?
前言:
关于System V下的通信方式,我们只是对共享内存做深度的处理,而对于消息队列和信号量我们并不会特别在意,一下我将粗略的介绍一下关于消息队列,但是信号量这一部分,还有一些新的知识点需要好好聊聊。
🎃消息队列:
消息队列(Message Queue)是操作系统提供的一种进程间通信(IPC,Inter-Process Communication)机制,允许进程通过消息的形式进行异步通信。消息队列为进程间提供了一个有序的、独立于进程之外的消息缓冲区,进程可以通过向消息队列发送和接收消息来进行数据交换。
1. 消息队列的基本概念
- 异步通信:消息发送进程和接收进程之间是异步的,即发送者可以发送消息后立即返回,无需等待接收者处理;同样,接收者在准备好时可以读取消息,而无需等待发送者。
- 持久性:消息队列中的消息是持久的,消息一旦被发送,它们会保留在队列中,直到被接收进程读取或队列被显式删除。
- 顺序性:消息以队列的形式存储,发送的顺序决定了消息的顺序。接收者可以按照消息的优先级或先进先出的顺序读取消息。
2. 消息队列的特点
- 异步通信:消息队列允许发送进程和接收进程以不同时执行,发送进程不需要等待接收进程处理消息。
- 持久性:消息队列是内核管理的,在消息被读取之前,它们会一直保存在队列中,即使发送者和接收者都已经终止。
- 消息有优先级:消息可以按照优先级或FIFO(先进先出)的方式传递,接收者可以按优先级顺序或按时间顺序接收消息。
3. 常见的消息队列操作(Linux IPC)
在Linux中,消息队列是通过系统调用来实现的。下面是与消息队列相关的常见系统调用及其功能:
1) msgget:创建或获取消息队列
int msgget(key_t key, int msgflg);
key:消息队列的唯一标识符,由用户定义。可以通过ftok()函数生成。msgflg:消息队列的标志位。可以是IPC_CREAT(如果消息队列不存在则创建),以及权限标志如0666等。- 返回值:返回消息队列的标识符(
msqid),后续操作基于此ID。
2) msgsnd:发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:消息队列标识符,由msgget()返回。msgp:指向消息结构体的指针,该结构体包含消息类型和消息内容。msgsz:消息的大小。msgflg:控制操作的标志位。如果队列满了,IPC_NOWAIT可以避免发送者被阻塞。- 返回值:成功时返回
0,失败时返回-1并设置errno。
消息结构通常定义如下:
struct msgbuf {long mtype; // 消息类型char mtext[1]; // 消息内容
};
3) msgrcv:接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msqid:消息队列标识符。msgp:指向存储接收消息的结构体的指针。msgsz:要接收的最大消息大小。msgtyp:指定要接收的消息类型。如果为0,则接收队列中的第一条消息。msgflg:控制操作的标志位。可以使用IPC_NOWAIT来防止阻塞,或者使用MSG_EXCEPT来接收非指定类型的消息。- 返回值:返回读取到的字节数,失败时返回
-1并设置errno。
4) msgctl:控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
-
msqid:消息队列标识符。 -
cmd:控制操作,可以是以下值:
IPC_STAT:获取消息队列的状态。IPC_SET:设置消息队列的状态。IPC_RMID:删除消息队列。
-
buf:用于存储或设置消息队列的状态信息,msqid_ds结构体包含权限、最后的操作时间、消息数等信息。
4. 消息队列的基本操作示例(Linux C代码)
以下是一个简单的消息队列示例代码,展示如何创建消息队列、发送消息和接收消息。
消息发送示例:
c复制代码#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>struct msgbuf {long mtype; // 消息类型char mtext[100]; // 消息内容
};int main() {key_t key;int msgid;// 生成唯一的keykey = ftok("progfile", 65);// 创建消息队列msgid = msgget(key, 0666 | IPC_CREAT);// 准备要发送的消息struct msgbuf message;message.mtype = 1; // 消息类型strcpy(message.mtext, "Hello World!");// 发送消息到队列msgsnd(msgid, &message, sizeof(message.mtext), 0);printf("Message Sent: %s\n", message.mtext);return 0;
}
消息接收示例:
c复制代码#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>struct msgbuf {long mtype; // 消息类型char mtext[100]; // 消息内容
};int main() {key_t key;int msgid;// 生成唯一的keykey = ftok("progfile", 65);// 获取消息队列msgid = msgget(key, 0666 | IPC_CREAT);// 准备接收消息struct msgbuf message;// 接收类型为1的消息msgrcv(msgid, &message, sizeof(message.mtext), 1, 0);// 显示消息内容printf("Message Received: %s\n", message.mtext);return 0;
}
删除消息队列:
c复制代码#include <sys/ipc.h>
#include <sys/msg.h>int main() {key_t key;int msgid;// 生成唯一的keykey = ftok("progfile", 65);// 获取消息队列msgid = msgget(key, 0666 | IPC_CREAT);// 删除消息队列msgctl(msgid, IPC_RMID, NULL);return 0;
}
5. 消息队列的优缺点
优点:
- 异步处理:发送进程不必等待接收进程,可以提高系统的并发性和响应能力。
- 持久性:消息在队列中保存,直到接收者取走消息或队列被删除,即使发送者和接收者的生命周期不同步。
- 易用性:消息队列通过消息类型支持不同的消息分类,允许接收进程选择性读取某一类型的消息。
缺点:
- 容量限制:消息队列有大小限制,如果消息队列已满,发送进程可能会被阻塞(除非设置非阻塞标志)。
- 管理复杂性:消息队列是内核资源,使用后需要手动清理,未清理的消息队列可能会长期占用系统资源。
- 不适合大量数据传输:消息队列更适合传递较小的数据,过大的数据块可能会影响系统性能。
6. 消息队列的应用场景
- 进程间通信:消息队列用于不同进程之间的数据交换,例如不同模块之间的数据传递。
- 任务调度:某些系统通过消息队列进行任务调度,工作进程从队列中取任务执行。
- 日志系统:系统日志可以通过消息队列集中到一个日志处理进程来进行统一的日志存储或分析。
消息队列是一种常用的进程间通信机制,支持异步数据传输和灵活的消息管理。通过msgget、msgsnd、msgrcv等系统调用,进程可以方便地将消息发送到队列中并从中读取消息。虽然消息队列有一些限制,比如队列大小的限制和内核资源的消耗,但它在许多系统中仍然是一个高效的通信工具。
🎃信号量:
❤️五个概念:
- 多个进程(执行流)想要实现通信,都必须在内核中看到同一份资源,这个资源成为公共资源(共享资源)。
- 而被保护起来的资源就叫——临界资源
- 而保护的方式分为同步和互斥,而互斥是任何一个时刻只能有一个进程在访问公共资源。而以互斥方式保护的共享资源就是临界资源。
- 资源一定是要被访问的,而且是通过代码访问的。(代码又会分为“存在访问共享资源的”和“不存在访问共享资源的”。对于上述这两种情况,分别称为——临界区和非临界区。
- 所谓利用互斥保护共享资源使其变为临界资源,本质是对访问共享资源的代码进行保护。

❤️对信号量的理解?
信号量(Semaphore)是一种用于控制对共享资源的访问的同步机制,广泛应用于多线程和多进程编程中。信号量可以用来解决临界区问题,防止竞争条件,并确保资源的互斥访问。(简单来说,是用来保护临界资源的)
🍤对于不整体使用的资源:

所以对临界资源的保护其实就是设置一个计数器,每次访问前先申请访问,访问通过了才能访问,访问完成后又会有一个退出操作。因此保护临界资源的信号量本质就是一个计数器!
电影院:临界资源
买票:申请信号量 ————> 本质就是对公共资源的一种预定机制
票数:信号量的初始值步骤:
- 申请信号量
- 访问临界资源
- 释放信号量
🍚对于整体使用的资源:

🍗那我可不可以使用全局变量?
意思是,既然信号量是一个计数器,那我可不可以直接使用一个全局变量来表示计数器,想着可不可以完全替代信号量呢?
————不能!
-
全局变量不能被所有进程看到,因为进程之间具有独立性,而父子进程却很有可能发生写实拷贝。
-
不是原子的。
-
什么是原子操作?
**原子操作(Atomic Operation)**是指一个操作要么完整地执行,要么完全不执行。在多线程/多进程环境下,原子操作可以确保操作的完整性,不会被其他线程/进程打断。
而使用全局变量作为计数器时,增加和减少计数的操作通常需要多个步骤,比如:
- 读取全局变量的值
- 对值进行修改
- 将修改后的值写回全局变量
这三个步骤并不是一个原子操作。在多线程/进程环境下,如果两个线程/进程同时执行这三个步骤,就可能出现竞争条件(race condition),导致计数器的值不准确。
比如:
- 进程A读取计数器值为10
- 进程B也读取计数器值为10
- 进程A将值加1写回为11
- 进程B将值加1写回为11
此时,计数器的值应该是12,但实际只变成了11,出现了错误。
所以还得是信号量,不能是任何什么全局变量这种非原子的。
-
所以就得让多个进程看到一个信号量(计数器)
那就说明这个信号量本质就是一个公共资源!
既然你作为信号量,你的任务是保证其它临界资源的安全,那首先你得保证自己是安全的!
有很多方法保证信号量自身是安全的,那些操作我们以后讲,不过现在我们可以就原子性来讲讲。

-
信号量的核心操作 P(wait) 和 V(signal) 都是原子操作。
-
即这些操作要么完全执行,要么完全不执行,中间不会被中断,再按照上面局列举的例子就能理解如何保护临界资源的。
OS是如何把共享内存、消息队列、信号量统一管理起来的?
先组织,再描述!

struct kern_ipc_perm 是在 Linux 内核中用于管理进程间通信(IPC)对象的权限结构体。它是内核中 ipc_perm 的扩展版本,特意用于对共享内存、消息队列、信号量等 System V IPC 机制进行权限管理和控制。在用户空间中,ipc_perm 提供的是一个简化版的权限结构,而 kern_ipc_perm 则是内核用来管理这些权限的完整结构。
struct ipc_id_ary 是 Linux 内核中用于管理 System V IPC 对象(如共享内存、消息队列、信号量)的数据结构之一。它的主要作用是管理和跟踪所有的 IPC 资源,并存储这些 IPC 资源的标识符和相关信息。
IPC(进程间通信)资源在内核中通常通过索引和标识符(shmid、msqid、semid 等)进行管理。ipc_id_ary 是一个数组结构,用于保存 IPC 资源的 ID 和对应的数据结构,通常包括每种 IPC 对象类型(共享内存、消息队列、信号量)的标识符和状态信息。
你每创建一个共享内存或者消息队列,本质就是先进行一次struct kern_ipc_perm对象实例化,这里包含了该共享内存的key和序列号seq,而struct kern_ipc_perm每次的创建都会由struct ipc_id_ary里的柔性数组做管理,这里就是你每一次创建一个共享内存,我这里的下标就会加一,这也就是为什么你每次拿到shmid都会在上次的基础上加一,因此shmid本质就是struct ipd_id_ary里的柔性数组的下标,而每当你释放共享内存。
序列号的递增:共享内存段删除时,内核不会重新使用之前的序列号。相反,它会递增序列号,这样下次创建共享内存段时,即使使用相同的索引位置,生成的
shmid也不同。避免重复使用相同的
shmid:递增序列号的目的是为了防止系统意外地重新使用旧的shmid。这可以防止进程在使用过期或无效的shmid时产生意外行为。
现在我们可以说完成了进程间通信的话题,管道是在内核中对缓冲区实现通信,命名管道则是对文件,共享内存则是对一个数组,不过是在用户层面上的。下一章我们将开启Linux信号。
相关文章:
简单聊聊System V下的IPC + 内核是如何管理该IPC
文章目录 前言:🎃消息队列:1. **消息队列的基本概念**2. **消息队列的特点**3. **常见的消息队列操作(Linux IPC)****1) msgget:创建或获取消息队列****2) msgsnd:发送消息****3) msgrcv&#x…...
【WRF工具】服务器上安装convert_geotiff
【WRF工具】服务器上安装convert_geotiff convert_geotiff简介方法1:下载安装包后下载convert_geotiff依赖库安装库1:libtiff库2:sqlite库3:curl库4:projcmake更新(可选)库5:geotiff…...
RPC通讯基础原理
1.RPC(Remote Procedure Call)概述 RPC是一种通过网络从远程计算机上调用程序的技术,使得构建分布式计算更加容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性,提供一种透明调用机制,让使用者不…...
JavaScript 第18章:安全性
在JavaScript开发中,确保应用的安全性是非常重要的。下面我将根据你提到的几个方面来讲解如何增强Web应用程序的安全性。 XSS(跨站脚本)攻击防御 示例代码: function escapeHTML(unsafe) {return unsafe.replace(/&/g, &qu…...
基于workbox实现PWA预缓存能力
引言 Service Worker 是一项流行的技术,尽管在许多项目中尚未得到充分利用。基于本次项目首页加载优化的机会,决定尝试使用 Google 出品的 Workbox,以观察其优化效果。 开始 安装 项目使用 Webpack 打包,而 Workbox 提供了 We…...
探索Web3生态系统:社区、协议与参与者的角色
Web3代表着互联网的下一个演变阶段,旨在通过去中心化技术赋予用户更大的控制权和参与感。在这个新兴生态系统中,社区、协议和参与者扮演着不可或缺的角色,共同推动着Web3的建设与发展。 社区的核心作用 在Web3中,社区通过提供反馈…...
无人机电机故障率骤降:创新设计与六西格玛方法论双赢
项目背景 TBR-100是消费级无人机头部企业推出的主打消费级无人机,凭借其出色的续航能力和卓越的操控性,在市场上获得了广泛认可。在产品运行过程,用户反馈电机故障率偏高,尤其是在飞行一段时间后出现电机过热、损坏以及运行不稳定…...
samba禁用时拷贝服务器文件到本地的脚本
Android系统开发一般在ubuntu服务器上,我们办公电脑一般是windows。在将编译出来的模块push到板子上时,一般采用adb push 方式。 有时由于种种原因会出现服务器禁用了samba,导致无法直接用adb push 的情况。 下面介绍用winscp 走ssh 拷贝服…...
C#代码 串口通信晋中A2板,控制直流电机
1,在电脑中给晋中板中下载编译好的程序。 0x39 :开启电机的标识 代码: /********************************************************************************** **** 实验名称:串口通信实验 接线说明: 实验现象&…...
3 机器学习之假设空间
归纳(induction)与演绎(deduction)是科学推理的两大基本手段。前者是从特殊到一般的“泛化”(generalization)过程,即从具体的事实归结出一般性规律;后者则是从一般到特殊的“特化”(specialization)过程,即从基础原理推演出具体状况。例如&a…...
基于STM32的风速风向传感器设计
引言 本项目设计了一个基于STM32的风速和风向传感器系统,能够通过组合使用旋转式风速传感器和电子罗盘,实时测量风速和风向,并将数据通过显示屏或无线模块发送给用户。该系统适用于气象监测、环境监控、农业自动化等场景,具有准确…...
域名申请.
操作场景 Internet上有成千上万台主机,每一台主机都对应一个唯一的IP地址。IP地址因不具备实际意义,非常难于记忆,于是就产生了域名。 域名(Domain Name)是一串用点分隔的字符串组成的名称(例如huaweiclo…...
mysql5.7与mysql8.0身份认证插件的区别
MySQL 5.7 和 MySQL 8.0 在身份认证插件方面有一些重要的区别。这些变化主要集中在默认的身份验证插件、密码管理和安全性增强上。 默认身份验证插件 MySQL 5.7 默认插件: mysql_native_password mysql_native_password 是 MySQL 5.7 及更早版本中的默认身份验证插件。它使用…...
进化吧!原始人
如果你想体验一下人类的进化过程~ 如果你有一颗充满探索的好奇心~ 千万不要错过博主新开发的小游戏哦! 点击链接,立即体验! 🙋 欢迎来到冒险互动游戏《进化吧原始人》! 🦍 在这里,你将扮演一…...
SaaS架构:中央库存系统架构设计
大家好,我是汤师爷~ 近年来,越来越多的零售企业大力发展全渠道业务。在销售额增长上,通过线上的小程序、直播、平台渠道等方式,拓展流量变现渠道。在会员增长方面,通过多样的互动方式,全渠道触达消费者&am…...
C语言中点操作符(.)和箭头操作符(->)的区别
在C语言中,点操作符(.)和箭头操作符(->)用于访问结构体的成员,但它们的使用方式有所不同。以下是具体介绍: 点操作符(.)的使用 直接访问结构体变量的成员:…...
基于FPGA的以太网设计(一)
以太网简介 以太网(Ethernet)是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以太网的技术标准,它规定了包括物理层的连线、电子信号和介质访问控制的内容。以太网是目前应用最普遍的局域网技术,取代了其他局域网标准如…...
Insert into on duplicate key update 死锁问题解析
Insert into on duplicate key update 死锁问题解析 背景 前段时间的需求中有这个么一个场景,每天早上需要通过定时任务到不同的平台拉取一些广告投放的相关数据,涉及的表比较多,数据量也比较大,有的需要全量同步,有…...
Apache Lucene 10 已发布!Lucene 硬件效率改进及其他改进
作者:来自 Elastic Adrien Grand Apache Lucene 10 刚刚发布,重点关注硬件效率!查看主要版本亮点。 Apache Lucene 10 终于发布了!自 Lucene 9.0(于 2021 年 12 月发布,距今已有近 3 年)以来&a…...
【SQL】SQL查询语句
目录 🎄 基本查询语法 ⭐查询多个字段 ⭐设置别名 ⭐去除重复记录 ⭐ 数据准备 ⭐ 案例 🎄 条件查询 ⭐ 语法 ⭐ 案例 🎄 聚合函数 ⭐ 介绍 ⭐ 常见的聚合函数 ⭐ 语法 ⭐ 案例 🎄 分组查询 ⭐ 语法 ⭐ where与having的区…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
