Linux多进程和多线程(五)进程间通信-消息队列

  • 多进程(五)
    • 进程间通信
      • 消息队列
    • ftok()函数
    • 创建消息队列
      • 创建消息队列示例
    • msgctl 函数
    • 示例:在上⼀个示例的基础上,加上删除队列的代码
  • 发送消息
    • 示例:
  • 接收消息
  • 示例

多进程(五)

进程间通信

消息队列

消息队列是一种进程间通信机制,它允许两个或多个进程之间进行通信。

消息队列的实现依赖于操作系统提供的消息队列机制,它可以实现不同进程之间的数据交换。

IPC : Inter-Process Communication (进程间通讯)

System V是早期的UNIX系统,曾经被成为AT & T System V,是unix操作系统中比较重要的一个分支
现在的Linux操作系统也支持System V IPC

System V IPC 对象共有三种:

消息队列共享内存信号量

System V IPC是由内核维护的若干个对象,通过ipcs命令查询

在这里插入图片描述

每个IPC对象都有自己的唯一ID,可以通过ftok()函数生成IPC对象的ID
消息队列是属于 sytem ipc 的⼀种, 由内核维护与管理 可以通过 ipcs -q 查看

ftok()函数

函数头文件:

#include <sys/ipc.h>

函数原型:

key_t ftok(const char *pathname, int proj_id);

参数说明:

  • pathname: 要生成IPC对象的路径名

  • proj_id: 项目ID,用于区分不同IPC对象

  • 每个存在的文件都有一个id,叫做inode节点号,可以通过ll 命令查询

  • inode节点号 + proj_id(低8bit) 生成key_t类型的值,作为IPC对象的ID

  • key_t类型的值可以用ftok()函数生成,也可以用mkkey()函数生成

函数返回值:

  • 成功: 返回一个key_t类型的整数,该整数是IPC对象的ID
  • 失败: 返回-1,并设置errno

创建消息队列

函数头文件:

#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>

函数原型:

int msgget(key_t key, int msgflg);

参数说明:

  • key: 要生成IPC对象的ID
  • msgflg: 标志位,用于设置消息队列的访问模式,可取值如下:
    • IPC_CREAT: 如果key对应的消息队列不存在,则创建该消息队列
    • IPC_EXCL: 如果key对应的消息队列已经存在,则返回错误
    • 0: 打开已存在的消息队列
    • 权限控制标志: 如0666,表示创建的消息队列具有读写权限

函数返回值:

  • 成功: 返回消息队列的ID
  • 失败: 返回-1,并设置errno

创建消息队列示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//创建消息队列#define MSG_PATH "."
#define MSG_ID 88
int main(){key_t key;//消息队列的keykey= ftok(MSG_PATH,MSG_ID);//通过文件路径和ID生成keyif(key==-1){printf("ftok()");exit(EXIT_FAILURE);}int msgid= msgget(key,IPC_CREAT|0666);//创建消息队列if(msgid==-1){printf("msgget()");exit(EXIT_FAILURE);}printf("Message Queue ID: %d\n",msgid);return 0;
}

运行结果:

在这里插入图片描述

msgctl 函数

功能: 操作消息队列

函数头文件:

#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/msg.h>

函数原型:

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

参数说明:

  • msqid: 要操作的消息队列ID
  • cmd: 操作命令,可取值如下:
    • IPC_STAT: 获取消息队列的状态信息 //和struct msqid_ds *buf参数一起使用
    • IPC_SET: 设置消息队列的状态信息 //和struct msqid_ds *buf参数一起使用
    • IPC_RMID: 删除消息队列 //使用这个命令时,第三个参数为NULL
  • buf: 消息队列属性结构体对象指针,用于设置或获取消息队列的状态信息,

函数返回值:

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

消息队列属性结构体定义如下:

struct msqid_ds
{
#ifdef __USE_TIME_BITS64
# include <bits/types/struct_msqid64_ds_helper.h>
#elsestruct ipc_perm msg_perm;	/* 描述操作权限的结构 */struct ipc_perm
{__key_t __key;				/* Key.  */__uid_t uid;					/* 所有者的用户 ID.  */__gid_t gid;					/* 所有者组 ID.  */__uid_t cuid;					/* 创作者的用户 ID.  */__gid_t cgid;					/* 创作者的组 ID.  */__mode_t mode;				/* 读/写权限.  */unsigned short int __seq;			/* 序列号.  */unsigned short int __pad2;  __syscall_ulong_t __glibc_reserved1; __syscall_ulong_t __glibc_reserved2;
};# if __TIMESIZE == 32__time_t msg_stime;		//上次发送消息的时间unsigned long int __msg_stime_high; __time_t msg_rtime;		//上次接收消息的时间unsigned long int __msg_rtime_high;__time_t msg_ctime;	//消息队列的创建时间unsigned long int __msg_ctime_high;
# else__time_t msg_stime;		//上次发送消息的时间__time_t msg_rtime;		//上次接收消息的时间__time_t msg_ctime;		//消息队列的创建时间
# endif__syscall_ulong_t __msg_cbytes;  //消息队列中消息的字节数msgqnum_t msg_qnum;		//消息队列中消息的数量__pid_t msg_lspid;		//最后发送消息的进程ID__syscall_ulong_t __glibc_reserved4; //保留__syscall_ulong_t __glibc_reserved5;//保留
#endif
};

示例:在上⼀个示例的基础上,加上删除队列的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//创建消息队列#define MSG_PATH "."
#define MSG_ID 88
int main(){key_t key;//消息队列的keykey= ftok(MSG_PATH,MSG_ID);//通过文件路径和ID生成keyif(key==-1){printf("ftok()");exit(EXIT_FAILURE);}int msgid= msgget(key,IPC_CREAT|0666);//创建消息队列if(msgid==-1){printf("msgget()");exit(EXIT_FAILURE);}printf("Message Queue ID: %d\n",msgid);int ret= msgctl(msgid,IPC_RMID,NULL);//删除消息队列if(ret==-1){printf("msgctl()");exit(EXIT_FAILURE);}printf("消息队列已删除.\n");return 0;
}

发送消息

发送消息队列的函数是msgsnd()
msgsnd函数是用于向System V消息队列发送消息的一个系统调用。消息队列是一种由操作系统提供的进程间通信(IPC)机制,允许一个进程发送消息并且另一个进程接收消息。以下是msgsnd函数的详细说明和用法。
函数头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

函数原型:

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

参数说明:

  • msqid: 要发送的消息队列ID

  • msgp: 要发送的消息内容指针

  • msgsz: 要发送的消息内容长度

  • msgflg: 标志位,用于设置消息发送的模式,可取值如下:

    • IPC_NOWAIT: 若消息队列已满,则立即返回错误 ,返回-1,并设置errno为EAGAIN
    • 0: 若消息队列已满,则阻塞等待直到消息队列空闲
    • 对发送消息来说,有意义的flags标志为IPC_NOWAIT,
    • 在消息队列没有足够的空间容纳要发送的数据时,设置了该标志,
    • 则msgsnd()函数立刻出错返回,
    • 否则发送消息的进程被阻塞,直至消息队列有空间或队列被删除时返回。

函数返回值:

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

在这里插入图片描述

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSG_PATH "/home/gopher"
#define MSG_ID 88//消息队列发送  MessageQueues2中接收
#define MSG_SZ 100
struct msgbuf{//消息队列结构long mtype;//消息类型char mtext[MSG_SZ];//消息内容
};
int main(){key_t key;//消息队列的key//通过文件路径和ID生成key,key= ftok(MSG_PATH,MSG_ID);if(key==-1){printf("ftok()");exit(EXIT_FAILURE);}printf("key: %d\n",key);//使用key 创建消息队列int msgid= msgget(key,IPC_CREAT|0666);if(msgid==-1){printf("msgget()");exit(EXIT_FAILURE);}printf("消息队列ID: %d\n",msgid);//准备消息模板struct msgbuf msg;//消息队列结构msg.mtype=101;//消息类型strcpy(msg.mtext,"Hello,world!");//消息内容//msgsnd函数第一个参数是消息队列ID,第二个参数是消息队列结构的指针,第三个参数是消息长度,第四个参数是消息类型int ret= msgsnd(msgid,(const void*)&msg,strlen(msg.mtext)+1,0);// 0: 若消息队列已满,则阻塞等待直到消息队列空闲if(ret==-1){printf("msgsnd()");exit(EXIT_FAILURE);}return 0;
}

常见错误

EINVAL: 无效的消息队列标识符或无效的消息大小。

EIDRM: 消息队列已被标记为删除。

EINTR: 调用被信号中断。

EAGAIN: 消息队列满,并且指定了IPC_NOWAIT标志。

接收消息

msgrcv函数是用于在System V消息队列中接收消息的函数。msgrcv函数从消息队列中读取消息,并从队列中删除该消息。以下是msgrcv函数的语法及其详细说明。

函数原型:


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

参数说明:

msqid: 消息队列标识符,通常由msgget函数返回。
msgp: 指向用户定义的消息缓冲区的指针。结构体中至少应包含一个long mtype成员,用于指定消息的类型。其余部分可根据需要定义为消息数据。
msgsz: 指定消息数据部分的最大字节数(不包括mtype成员的大小)。
msgtyp: 指定要接收的消息类型。如果msgtyp为零,则接收队列中的第一个消息。
msgflg: 操作标志,可以是以下值的按位或:IPC_NOWAIT: 如果没有合适的消息可供接收,函数立即返回而不是阻塞。MSG_EXCEPT: 接收不等于msgtyp的第一个消息。MSG_NOERROR: 如果消息过长,将其截断。

返回值:

  • 成功: 返回实际接收的消息的字节数。
  • 失败: 返回-1,并设置errno。

常见错误

EINVAL: 无效的消息队列标识符。

EINTR: 调用被信号中断。

E2BIG: 消息太长并且未指定MSG_NOERROR标志。

ENOMSG: 没有符合msgtyp条件的消息,并且未指定IPC_NOWAIT标志。

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSG_PATH "/home/gopher"
#define MSG_ID 88//消息队列接收
#define MSG_SZ 100
struct msgbuf{//消息队列结构long mtype;//消息类型char mtext[MSG_SZ];//消息内容
};
int main(){key_t key;//消息队列的key//通过文件路径和ID生成key,key= ftok(MSG_PATH,MSG_ID);if(key==-1){printf("ftok()");exit(EXIT_FAILURE);}printf("key: %d\n",key);//使用key 创建消息队列int msgid= msgget(key,IPC_CREAT|0666);if(msgid==-1){printf("msgget()");exit(EXIT_FAILURE);}printf("消息队列ID: %d\n",msgid);//准备消息模板struct msgbuf msg;//消息队列结构msg.mtype=101;//消息类型ssize_t nbytes;//接收到的字节数nbytes= msgrcv(msgid,(void*)&msg,MSG_SZ,101,0);//接收消息  //0接收第一条消息//MSG_SZ为msg能接受的最大字节数if(nbytes==-1){printf("msgrcv()");exit(EXIT_FAILURE);}printf("消息类型: %ld\n",msg.mtype);printf("已收到消息: %s\n",msg.mtext);return 0;
})");exit(EXIT_FAILURE);}printf("消息队列ID: %d\n",msgid);//准备消息模板struct msgbuf msg;//消息队列结构msg.mtype=101;//消息类型ssize_t nbytes;//接收到的字节数nbytes= msgrcv(msgid,(void*)&msg,MSG_SZ,101,0);//接收消息  //0接收第一条消息//MSG_SZ为msg能接受的最大字节数if(nbytes==-1){printf("msgrcv()");exit(EXIT_FAILURE);}printf("消息类型: %ld\n",msg.mtype);printf("已收到消息: %s\n",msg.mtext);return 0;
}

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

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

相关文章

LCD显示从电路IC 到 驱动编写调试

文章目录 LCD驱动电路IC简述Panel 模块驱动图示含义接口与连接 Panel内部驱动驱动原理框图TCON(Timing Controller):时序控制器。一、控制屏幕时序与信号驱动二、提升图像质量三、接口支持与兼容性四、市场应用广泛 Gate控制信号工作时序Source Driver IC原理框图 LCD驱动应该怎…

JAVA—图形化“登录,注册”界面

前言&#xff1a;学习了一段时间JAVA的swing组件&#xff0c;心血来潮写了一个登录&#xff0c;注册界面。 知道大伙喜欢美女&#xff0c;所以把用户登录界面背景设置成了beauty&#xff01; 所用知识基本上都属于swing组件&#xff1a; javax.siwng.JFrame; //窗体类 javax.sw…

【第四套】华为 2024 年校招-硬件电源岗

1、 其他参数不变,当 LLC 谐振电路的 Lm 增⼤时&#xff0c;描述错误的是 A.⼯作频率范围变⼩ B.关断电流减⼩ C.关断损耗减⼩ D.谐振电感减⼩ 2、 五类双绞线带宽可达 A. 10MHZ B. 20 MHZ C. 1GHZ D. 100MHZ 3、 当⽇照条件达到⼀定程度时,太阳能电池由于⽇照的变化⽽引起较明…

MyBatis 插入数据库生成id问题

核心代码 Mapper配置文件 <!-- 批量插入标签并返回主键 --> <insert id"insertBatch" parameterType"list" useGeneratedKeys"true" keyProperty"tagId">INSERT INTO tag (label)VALUES<foreach collection"lis…

c++习题08-计算星期几

目录 一&#xff0c;问题 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;问题 二&#xff0c;思路 首先&#xff0c;需要注意到的是3^2000这个数值很大&#xff0c;已经远远超过了long long 数据类型能够表示的范围&#xff0c;如果想要使用指定的数据类型来保存…

14-18 2024 年影响企业 GenAI 的关键技术趋势

现在&#xff0c;大多数 .com 公司已于 2023 年更名为 .ai&#xff0c;那么价值万亿美元的问题是&#xff1a;接下来会发生什么&#xff1f;哪些关键障碍、工具、技术和方法将重塑格局 企业 AI 的不同之处在于&#xff0c;它专注于可衡量、可管理的输出&#xff0c;企业可以控…

Docker容器基础:Docker的安装与基本使用

Docker容器基础&#xff1a;Docker的安装与基本使用 前言 Docker是一种开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。本文将介绍Docker的安装…

前端Web开发HTML5+CSS3+移动web视频教程 Day4 CSS 第2天

P44 - P 四个知识点&#xff1a; 复合选择器 CSS特性 背景属性 显示模式 复合选择器 复合选择器仍然是选择器&#xff0c;只要是选择器&#xff0c;作用就是找标签。复合选择器就是把基础选择器进行组合使用。组合了之后就可以在大量的标签里面更快更精准地找标签了。找…

redis实现简单分布式锁

1.redisTemplate实现简单分布式锁 AutowiredRedisTemplate redisTemplate;/*** redis分布式锁演示案例&#xff0c;此处使用redisTemplate* param stockId 此处以扣减库存为例子&#xff0c;stockId代表要扣减库存的商品id,库存数据是提前存在redis的&#xff0c;并和数据库进…

Qt中线程的使用

目录 1 .QThread重要信号和函数 1.1 常用共用成员函数 1.2信号和槽函数 1.3静态函数 1.4 任务处理函数 2.关于QThread的依附问题&#xff1a; 3.关于connect连接 4.QThread的使用 5.线程池QThreadPool 5.1. 线程池的原理 5.2&#xff0e;QRunable类 5.3. QThreadPoo…

Java8新特性常见用法

Java8新特性 示例类Stream API 使用示例forEach:遍历Stream:创建流map:转换元素filter:过滤元素collect(收集元素) 和 Collectors(分组、连接)sorted 和 comparing(搭配排序)toMap:转换Map元素collectingAndThen:过滤掉相同数据toUpperCase:转大写distinct:去重c…

安装维修制氮设备的注意指南

制氮设备在许多工业领域都发挥着重要作用&#xff0c;无论是确保生产过程中的氮气供应&#xff0c;还是维持设备的稳定运行&#xff0c;正确的安装和维修都是关键。以下是一些重要的注意事项&#xff0c;帮助您顺利完成制氮设备的安装与维修工作。 一、安装注意事项 (一)选址与…

独孤思维:你自己都不相信的副业,怎么能赚钱

要明白&#xff0c;你做副业的目的是什么&#xff1f; 如果你打心眼里&#xff0c;看不上这个项目&#xff0c;或者心不甘情不愿的被动推进项目的实操。 那么我建议你直接放弃。 不要不情愿地去做。 不要当成任务去完成。 如果抱着这份心态去做副业。 你的副业&#xff0…

VUE自定义新增、复制、删除dom元素

功能需求&#xff0c;能灵活新增或删除一个dom元素&#xff0c;在此dom元素中还存在能灵活新增、删除的dom元素。实现后功能图如下&#xff1a; 点击新增策略&#xff0c;能新增整个策略dom 实现思路&#xff1a;定义一个数量和一个数组&#xff0c;然后使用循环遍历展示内容&a…

一种特殊的二叉树 哈夫曼树(Huffman Tree)

哈夫曼树(Huffman Tree)是一种特殊的二叉树,它在信息编码领域有着广泛的应用,特别是在数据压缩技术中。下面我将通过图文结合的方式,详细介绍哈夫曼树的概念、构建方法以及应用场景。 哈夫曼树的概念 哈夫曼树是一种特殊的二叉树,由David Huffman于1952年提出。它主要用…

将iStoreOS部署到VMware ESXi变成路由器

正文共&#xff1a;888 字 19 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面把iStoreOS部署到了VMware workstation上&#xff08;将iStoreOS部署到VMware Workstation&#xff09;。如果想把iStoreOS直接部署到ESXi上&#xff0c;你会发现转换镜像不能直接生成OVF或者OV…

React Navigation 和 Expo Router

React Navigation 是 React Native 社区最常用的导航库&#xff0c;其具有高度可定制性且性能良好的特性。它提供了一系列导航器&#xff08;如堆栈导航器、标签导航器、抽屉导航器等&#xff09;&#xff0c;可以满足绝大多数的页面导航需求。 Expo Router 是 Expo 官方最新发…

css+js实现导航栏色块跟随滑动+点击后增加样式

这篇文章&#xff0c;我给大家分享一个导航菜单的效果。用cssJS实现&#xff0c;效果如图&#xff1a; 本例实现效果&#xff1a;当鼠标移动到其他菜单项时&#xff0c;会有个背景色块跟随鼠标横向平滑移动。当鼠标点击后&#xff0c;被点击的菜单名称文字字体会加粗。 现在&…

《数字图像处理与机器视觉》案例四 基于分水岭算法的粘连物体的分割与计数

一、引言 分水岭算法&#xff08;Watershed Algorithm&#xff09;&#xff0c;是一种基于拓扑理论的数学形态学的分割方法&#xff0c;其基本思想是把图像看作是测地学上的拓扑地貌&#xff0c;图像中每一点像素的灰度值表示该点的海拔高度&#xff0c;每一个局部极小值及其影…

SpringBoot 集成Swagger在线接口文档 接口注解

介绍 Swagger接口文档是一种自动生成、描述、调用和可视化的RESTful风格Web服务接口文档的工具。它通过一系列的规范和自动化工具&#xff0c;极大地简化了后端开发人员与前端开发人员之间的协作。 依赖 <!--swagger--> <dependency><groupId>io.springfo…