【Linux】Linux进程间通信(四)

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:Linux
🎯长路漫漫浩浩,万事皆有期待

上一篇博客:【Linux】Linux进程间通信(三)

文章目录

  • system V进程间通信
    • System V消息队列
      • 消息队列的基本原理
      • 消息队列数据结构
      • 消息队列的创建
      • 消息队列的释放
      • 向消息队列发送数据
      • 从消息队列获取数据
    • System V信号量
      • 信号量相关概念
      • 信号量数据结构
      • 信号量相关函数
      • 进程互斥
    • system V IPC联系
  • 总结:

system V进程间通信

System V消息队列

消息队列的基本原理

消息队列实际上就是在系统当中创建了一个队列,队列当中的每个成员都是一个数据块,这些数据块都由类型和信息两部分构成,两个互相通信的进程通过某种方式看到同一个消息队列,这两个进程向对方发数据时,都在消息队列的队尾添加数据块,这两个进程获取数据块时,都在消息队列的队头取数据块。在这里插入图片描述

其中消息队列当中的某一个数据块是由谁发送给谁的,取决于数据块的类型。

总结一下:

消息队列提供了一个从一个进程向另一个进程发送数据块的方法。
每个数据块都被认为是有一个类型的,接收者进程接收的数据块可以有不同的类型值。
和共享内存一样,消息队列的资源也必须自行删除,否则不会自动清除,因为system V IPC资源的生命周期是随内核的。

消息队列数据结构

当然,系统当中也可能会存在大量的消息队列,系统一定也要为消息队列维护相关的内核数据结构。

消息队列的数据结构如下:

struct msqid_ds {
	struct ipc_perm msg_perm;
	struct msg *msg_first;      /* first message on queue,unused  */
	struct msg *msg_last;       /* last message in queue,unused */
	__kernel_time_t msg_stime;  /* last msgsnd time */
	__kernel_time_t msg_rtime;  /* last msgrcv time */
	__kernel_time_t msg_ctime;  /* last change time */
	unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
	unsigned long  msg_lqbytes; /* ditto */
	unsigned short msg_cbytes;  /* current number of bytes on queue */
	unsigned short msg_qnum;    /* number of messages in queue */
	unsigned short msg_qbytes;  /* max number of bytes on queue */
	__kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
	__kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};

可以看到消息队列数据结构的第一个成员是msg_perm,它和shm_perm是同一个类型的结构体变量,ipc_perm结构体的定义如下:

struct ipc_perm{
	__kernel_key_t  key;
	__kernel_uid_t  uid;
	__kernel_gid_t  gid;
	__kernel_uid_t  cuid;
	__kernel_gid_t  cgid;
	__kernel_mode_t mode;
	unsigned short  seq;
};

记录一下:

共享内存的数据结构msqid_ds和ipc_perm结构体分别在/usr/include/linux/msg.h和/usr/include/linux/ipc.h中定义。

消息队列的创建

创建消息队列我们需要用msgget函数,msgget函数的函数原型如下:

int msgget(key_t key, int msgflg);

说明一下:

创建消息队列也需要使用ftok函数生成一个key值,这个key值作为msgget函数的第一个参数。
msgget函数的第二个参数,与创建共享内存时使用的shmget函数的第三个参数相同。
消息队列创建成功时,msgget函数返回的一个有效的消息队列标识符(用户层标识符)

消息队列的释放

释放消息队列我们需要用msgctl函数,msgctl函数的函数原型如下:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

说明一下:
msgctl函数的参数与释放共享内存时使用的shmctl函数的三个参数相同,只不过msgctl函数的第三个参数传入的是消息队列的相关数据结构。

向消息队列发送数据

向消息队列发送数据我们需要用msgsnd函数,msgsnd函数的函数原型如下:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msgsnd函数的参数说明:

第一个参数msqid,表示消息队列的用户级标识符。
第二个参数msgp,表示待发送的数据块。
第三个参数msgsz,表示所发送数据块的大小
第四个参数msgflg,表示发送数据块的方式,一般默认为0即可。

msgsnd函数的返回值说明:
msgsnd调用成功,返回0。
msgsnd调用失败,返回-1。

其中msgsnd函数的第二个参数必须为以下结构:

struct msgbuf{
	long mtype;       /* message type, must be > 0 */
	char mtext[1];    /* message data */
};

注意: 该结构当中的第二个成员mtext即为待发送的信息,当我们定义该结构时,mtext的大小可以自己指定。

从消息队列获取数据

从消息队列获取数据我们需要用msgrcv函数,msgrcv函数的函数原型如下:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msgrcv函数的参数说明:

第一个参数msqid,表示消息队列的用户级标识符。
第二个参数msgp,表示获取到的数据块,是一个输出型参数。
第三个参数msgsz,表示要获取数据块的大小
第四个参数msgtyp,表示要接收数据块的类型。

msgrcv函数的返回值说明:
msgsnd调用成功,返回实际获取到mtext数组中的字节数。
msgsnd调用失败,返回-1。

System V信号量

信号量相关概念

由于进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系叫做进程互斥。
系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
在进程中涉及到临界资源的程序段叫临界区。
IPC资源必须删除,否则不会自动删除,因为system V IPC的生命周期随内核。

信号量数据结构

在系统当中也为信号量维护了相关的内核数据结构。

信号量的数据结构如下:

struct semid_ds {
	struct ipc_perm sem_perm;       /* permissions .. see ipc.h */
	__kernel_time_t sem_otime;      /* last semop time */
	__kernel_time_t sem_ctime;      /* last change time */
	struct sem  *sem_base;      /* ptr to first semaphore in array */
	struct sem_queue *sem_pending;      /* pending operations to be processed */
	struct sem_queue **sem_pending_last;    /* last pending operation */
	struct sem_undo *undo;          /* undo requests on this array */
	unsigned short  sem_nsems;      /* no. of semaphores in array */
};

信号量数据结构的第一个成员也是ipc_perm类型的结构体变量,ipc_perm结构体的定义如下:

struct ipc_perm{
	__kernel_key_t  key;
	__kernel_uid_t  uid;
	__kernel_gid_t  gid;
	__kernel_uid_t  cuid;
	__kernel_gid_t  cgid;
	__kernel_mode_t mode;
	unsigned short  seq;
};

记录一下:
共享内存的数据结构msqid_ds和ipc_perm结构体分别在/usr/include/linux/sem.h和/usr/include/linux/ipc.h中定义。

信号量相关函数

信号量集的创建

创建信号量集我们需要用semget函数,semget函数的函数原型如下:

int semget(key_t key, int nsems, int semflg);

说明一下:

创建信号量集也需要使用ftok函数生成一个key值,这个key值作为semget函数的第一个参数。
semget函数的第二个参数nsems,表示创建信号量的个数。
semget函数的第三个参数,与创建共享内存时使用的shmget函数的第三个参数相同。
信号量集创建成功时,semget函数返回的一个有效的信号量集标识符(用户层标识符)

信号量集的删除

删除信号量集我们需要用semctl函数,semctl函数的函数原型如下:

int semctl(int semid, int semnum, int cmd, ...);

信号量集的操作

对信号量集进行操作我们需要用semop函数,semop函数的函数原型如下:

int semop(int semid, struct sembuf *sops, unsigned nsops);

进程互斥

进程间通信通过共享资源来实现,这虽然解决了通信的问题,但是也引入了新的问题,那就是通信进程间共用的临界资源,若是不对临界资源进行保护,就可能产生各个进程从临界资源获取的数据不一致等问题。

保护临界资源的本质是保护临界区,我们把进程代码中访问临界资源的代码称之为临界区,信号量就是用来保护临界区的,信号量分为二元信号量和多元信号量。

比如当前有一块大小为100字节的资源,我们若是一25字节为一份,那么该资源可以被分为4份,那么此时这块资源可以由4个信号量进行标识。
在这里插入图片描述

信号量本质是一个计数器,在二元信号量中,信号量的个数为1(相当于将临界资源看成一整块),二元信号量本质解决了临界资源的互斥问题,以下面的伪代码进行解释:

在这里插入图片描述

根据以上代码,当进程A申请访问共享内存资源时,如果此时sem为1(sem代表当前信号量个数),则进程A申请资源成功,此时需要将sem减减,然后进程A就可以对共享内存进行一系列操作,但是在进程A在访问共享内存时,若是进程B申请访问该共享内存资源,此时sem就为0了,那么这时进程B会被挂起,直到进程A访问共享内存结束后将sem加加,此时才会将进程B唤起,然后进程B再对该共享内存进行访问操作。

在这种情况下,无论什么时候都只会有一个进程在对同一份共享内存进行访问操作,也就解决了临界资源的互斥问题。

实际上,代码中计数器sem减减的操作就叫做P操作,而计数器加加的操作就叫做V操作,P操作就是申请信号量,而V操作就是释放信号量。
在这里插入图片描述

system V IPC联系

通过对system V系列进程间通信的学习,可以发现共享内存、消息队列以及信号量,虽然它们内部的属性差别很大,但是维护它们的数据结构的第一个成员确实一样的,都是ipc_perm类型的成员变量。

这样设计的好处就是,在操作系统内可以定义一个struct ipc_perm类型的数组,此时每当我们申请一个IPC资源,就在该数组当中开辟一个这样的结构。
在这里插入图片描述

也就是说,在内核当中只需要将所有的IPC资源的ipc_perm成员组织成数组的样子,然后用切片的方式获取到该IPC资源的起始地址,然后就可以访问该IPC资源的每一个成员了。

总结:

今天我们继续学习了Linux进程间通信的相关知识,了解了system V进程间通信等 。接下来,我们将继续学习Linux的其他知识。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

flask分页宏增加更多参数

背景:我正在开发一个博客,核心的两个model是文章和文章类别。 现在想要实现的功能是:点击一个文章类别,以分页的形式显示这个文章类别下的所有文章,类似这种效果。 参考的书中分页宏只接受页数这一个参数,…

NLP论文阅读记录 - 2021 | WOS MAPGN:用于序列到序列预训练的掩码指针生成器网络

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.前提三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 MAPGN: MASKED POINTER-GENERATOR NETWORK FOR SEQUENCE-TO-SEQUENCE…

python常用库

常见模块解析 1. math库 数学函数 函数返回值 ( 描述 )abs(x)返回数字的绝对值&#xff0c;如abs(-10) 返回 10ceil(x)返回数字的上入整数&#xff0c;如math.ceil(4.1) 返回 5cmp(x, y)如果 x < y 返回 -1, 如果 x y 返回 0, 如果 x > y 返回 1。 **Python 3 已废弃…

Pandas.DataFrame.groupby() 数据分组(数据透视、分类汇总) 详解 含代码 含测试数据集 随Pandas版本持续更新

关于Pandas版本&#xff1a; 本文基于 pandas2.1.2 编写。 关于本文内容更新&#xff1a; 随着pandas的stable版本更迭&#xff0c;本文持续更新&#xff0c;不断完善补充。 Pandas稳定版更新及变动内容整合专题&#xff1a; Pandas稳定版更新及变动迭持续更新。 Pandas API参…

jquery动态引入js和css

直接上代码吧&#xff0c;但是有时候这个方法会失败&#xff0c;js文件里面的方法不生效&#xff0c;原因还在找 // 动态引入cssvar cssFileUrl index.css;$("head").append("<link>");css $("head").children(":last");css.a…

Codeforces Round 803 (Div. 2) E. PermutationForces II(思维题 位置序列)

题目 给定长为n(n<2e5)的两个序列a和b&#xff0c; a为n的一个排列&#xff0c; b也为n的一个排列&#xff0c;但有一些位置被-1替换了&#xff0c;保证没被替换的位置在[1,n]之间且两两不同 你有一个距离最大限制s&#xff0c;你可以执行n次操作&#xff0c; 第i次操作…

【现代密码学基础】详解完美安全与不可区分安全

目录 一. 介绍 二. 不可区分性试验 三. 不可区分性与完美安全 四. 例题 五. 小结 一. 介绍 敌手完美不可区分&#xff0c;英文写做perfect adversarial indistinguishability&#xff0c;其中adversarial经常被省略不写&#xff0c;在密码学的论文中经常被简称为IND安全。…

视频增强修复Topaz Video AI

Topaz Video AI是一款强大的视频增强软件&#xff0c;利用人工智能技术对数千个视频进行训练&#xff0c;结合多个输入视频的帧信息来提高素材的分辨率。该软件可将视频的分辨率提高到最高8K&#xff0c;并保持真实的细节和运动一致性。同时&#xff0c;它还能自动修复视频中的…

Linux系统CPU持续飙高,如何排查?

一、检查CPU使用率 首先在Linux系统中检查CPU使用率。可以通过在命令行中输入top或htop命令来查看当前系统中各个进程的CPU使用率。如果CPU使用率大于80%&#xff0c;则可以考虑进行排查。 $ top 二、检查系统负载 另外可以使用uptime命令来查看系统的平均负载情况。 $ upti…

DiffMIC:融合局部和全局分析,基于扩散模型的医学图像分类方法

DiffMIC&#xff1a;基于扩散模型的医学图像分类方法 DiffMIC的核心思想糖尿病视网膜病变分级 网络结构去噪扩散模型&#xff1a;提升特征清晰度双粒度条件引导&#xff08;DCG&#xff09;&#xff1a;融合局部和全局分析条件特定的最大均值差异&#xff08;MMD&#xff09;正…

【Java】JDBC练习

JDBC练习 环境准备 -- 删除tb_brand表 drop table if exists tb_brand; -- 创建tb_brand表 create table tb_brand (-- id 主键id int primary key auto_increment,-- 品牌名称brand_name varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered …

C++设计模式之 模板方法模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【设计模式大纲】 【简介】 --什么是模板方法模式&#xff08;第18种设计模式&#xff09; 模板方法模式&#xff0…

《Linux高性能服务器编程》笔记02

Linux高性能服务器编程 参考 Linux高性能服务器编程源码: https://github.com/raichen/LinuxServerCodes 豆瓣: Linux高性能服务器编程 文章目录 Linux高性能服务器编程第06章 高级I/O函数6.1 pipe函数6.2 dup函数和dup2函数6.3 readv 函数和writev 函数6.4 sendfile 函数6.…

基于SSM的KTV包厢管理系统(有报告)。Javaee项目,ssm项目。

演示视频&#xff1a; 基于SSM的KTV包厢管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过…

软件测试|sqlalchemy一对一关系详解

简介 SQLAlchemy 是一个强大的 Python ORM&#xff08;对象关系映射&#xff09;库&#xff0c;它允许我们将数据库表映射到 Python 对象&#xff0c;并提供了丰富的关系模型来处理不同类型的关系&#xff0c;包括一对一关系。在本文中&#xff0c;我们将深入探讨 SQLAlchemy …

后台管理系统: 数据可视化基础

数据可视化简单理解&#xff0c;就是将数据转换成易于人员辨识和理解的视觉表现形式&#xff0c;如各种 2D 图表、3D 图表、地图、矢量图等等。 例如Excel等等 canvas <canvas> 标签只是图形容器&#xff0c;相当于一个画布&#xff0c;canvas 元素本身是没有绘图能力…

算法常用思路总结

思路 1. 求数组中最大最小值思路代码 2. 计算阶乘思路&#xff1a;代码&#xff1a; 3. 得到数字的每一位思路代码 4. 计算时间类型5. 最大公约数、最小公倍数6. 循环数组的思想题目&#xff1a;猴子选大王代码 补充经典例题1. 复试四则运算题目内容题解 2. 数列求和题目内容题…

安防监控系统EasyCVR平台用户调用设备参数,信息不返回是什么原因?

安防视频监控系统EasyCVR视频综合管理平台&#xff0c;采用了开放式的网络结构&#xff0c;平台能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;平台支持设备通过4G、5G、WIFI、有…

限流算法之流量控制的平滑之道:滑动时间窗算法

文章目录 引言简介优点缺点样例样例图样例代码 应用场景结论 引言 在互联网应用中&#xff0c;流量控制是一个重要的组件&#xff0c;用于防止系统过载和保护核心资源。常见的限流算法包括固定窗口算法和滑动时间窗算法。本文将重点介绍滑动时间窗算法&#xff0c;并分析其优缺…

掌握虚拟化:PVE平台安装教程与技术解析

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…