Linux进程间通信(三)-----System V消息队列

消息队列的概念及原理

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

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

总结一下:

  1. 消息队列提供了一个从一个进程向另一个进程发送数据块的方法。
  2. 每个数据块都被认为是有一个类型的,接收者进程接收的数据块可以有不同的类型值。
  3. 和共享内存一样,消息队列的资源也必须自行删除,否则不会自动清除,因为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_dsipc_perm结构体分别在/usr/include/linux/msg.h和/usr/include/linux/ipc.h中定义。

消息队列的创建

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

int msgget(key_t key, int msgflg);

说明一下:

  1. 创建消息队列也需要使用ftok函数生成一个key值,这个key值作为msgget函数的第一个参数。
  2. msgget函数的第二个参数,与创建共享内存时使用的shmget函数的第三个参数相同。
  3. 消息队列创建成功时,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;
};

进程互斥

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

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

        比如当前有一块大小为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资源的每一个成员了。

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

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

相关文章

STM32F1 - 中断优先级

Interrupt Priority 1> STM32F103ZET6异常向量表2> 中断优先级寄存器NVIC_IPRx3> 中断优先级分组4> 例程:设置EXTI4中断优先级5> 例程:设置SysTick中断优先级6> 为什么不能用NVIC_Init()设置Systick优先级?7> 函数NVIC_…

OpenCV 4基础篇| OpenCV简介

目录 1. 什么是OpenCV2. OpenCV的发展历程3. 为什么用OpenCV4. OpenCV应用领域5. OpenCV的功能模块5.1 基本模块5.2 扩展模块5.3 常用函数目录 1. 什么是OpenCV OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它…

CSS的注释:以“ /* ”开头,以“ */ ”结尾

CSS的注释:以“ /* ”开头,以“*/”结尾 CSS的注释: 以“ /* ”开头,以“ */ ”结尾 在CSS中,注释是一种非常重要的工具,它们可以帮助开发者记录代码的功能、用法或其他重要信息。这些信息对于理解代码、维护代码以及与他人合作都…

【网站项目】154智能无人仓库管理

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

AKamai破解初试

标准的TLS/AKamai绕过 ja3算法: GitHub - salesforce/ja3: JA3 is a standard for creating SSL client fingerprints in an easy to produce and shareable way. tls设备指纹测试: https://tls.browserleaks.com/json akm指纹 https://tls.peet.ws/api/all …

echarts制作两个柱状图

let colorList[#02ce8b,#ffbe62,#f17373]; let data1 [90,80,70,50] option { title:[{ // 第一个标题text: 环保检测, // 主标题textStyle: { // 主标题样式color: #333,fontWeight: bold,fontSize: 16},left: 20%, // 定位到适合的位置top: 10%, // 定位到适合的位置},{ //…

CSS之margin塌陷

margin塌陷 CSS中的外边距塌陷(Margin Collapse)问题是指在垂直方向上,当两个或多个块级元素的边距相遇时,它们之间的距离不是它们各自边距的总和,而是其中的最大值。这种现象主要出现在块级元素的上下外边距之间。 &…

一些配置问题记录

真的很感慨 为什么一开始的下载的软件还能用 卸载或重装后的软件总是存在各种各样的错误 真令人心烦 GNURADIO运行简单的采集信号程序报错, 其实不太理解为什么会出现这类错误,解决方法为 安装 jackd2 软件包,然后尝试手动启动 Jack 服务器…

【学网攻】 第(29)节 -- 综合实验二

系列文章目录 目录 系列文章目录 文章目录 前言 一、综合实验 二、实验 1.引入 实验目标 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻…

【开源】JAVA+Vue.js实现大学计算机课程管理平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

钡铼技术的LoRa网关实现智能电网监测与控制

钡铼技术的LoRa网关在智能电网监测与控制方面发挥着关键作用,为电力系统的安全运行和高效管理提供了重要支持。下面将详细介绍钡铼技术的LoRa网关如何实现智能电网监测与控制。 首先,钡铼技术的LoRa网关通过接入各类传感器和监测设备,实现对…

谷歌新动作:双子模型大放送,开发者福音来了!

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…