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

news2024/11/17 13:23:21
  • 多进程(五)
    • 进程间通信
      • 消息队列
    • 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;//消息队列的key
    key= ftok(MSG_PATH,MSG_ID);//通过文件路径和ID生成key
    if(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>
#else
  struct 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;//消息队列的key
    key= ftok(MSG_PATH,MSG_ID);//通过文件路径和ID生成key
    if(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.coloradmin.cn/o/1891329.html

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

相关文章

终身免费的Navicat数据库,不需要破解,官方支持

终身免费的Navicat数据库&#xff0c;不需要破解&#xff0c;官方支持 卸载了Navicat&#xff0c;很不爽上干货&#xff0c;Navicat免费版下载地址 卸载了Navicat&#xff0c;很不爽 公司不让用那些破解的数据库软件&#xff0c;之前一直使用Navicat。换了几款其他的数据库试了…

大数据开发如何快速进阶

目录 1. 个人经验与心得分享1.1 试错的价值与机会把握1.2 投入产出比的考量1.3 刻意练习与技能提升1.4 目标设定与职业规划1.5 自我驱动与成长1.6 第一性原理的应用 2. 大数据开发领域的挑战与机遇2.1 技术革新的挑战2.2 数据治理的难题2.3 人才短缺的问题2.4 投入产出比的考量…

电子部件烧录流程(仅供参考)

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;日常聊聊 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 部件烧录流程的详细步骤 1. 准备工作 2. 连接硬件 3. 配置烧录软件 4. 校验和设置 5. 开始烧录 6. 验证和测试 7. 断开…

Docker实现Redis主从,以及哨兵机制

Docker实现Redis主从,以及哨兵机制 目录 Docker实现Redis主从,以及哨兵机制准备Redis镜像创建Redis主节点配置文件启动Redis从节点确认主从连接哨兵主要功能配置哨兵文件创建Redis哨兵的Docker容器 要通过Docker实现Redis的主从&#xff08;master-slave&#xff09;复制&#…

亚太万人eVTOL展!2024深圳eVTOL将于9月登陆鹏城

2024年以来&#xff0c;北京、上海等十多个省市&#xff0c;先后发布了鼓励低空经济发展的行动方案&#xff0c;其中&#xff0c;eVTOL&#xff08;电动垂直起降航空器&#xff09;成为低空经济最火热的细分赛道。2023年&#xff0c;中国eVTOL产业规模达9.8亿元&#xff0c;同比…

Cloud Kernel SIG 双月动态:ANCK 发布 4.19 6.6 新版本,存储、内存、调度等新特性支持

Cloud Kernel SIG&#xff08;Special Interest Group&#xff09;&#xff1a;支撑龙蜥内核版本的研发、发布和服务&#xff0c;提供生产可用的高性价比内核产品。 本月度动态综合汇总了 5 月和 4 月双月项目动态&#xff1a; 01 SIG 整体进展 5 月 1. ANCK-6.6 release 6…

基于RAG(检索增强生成)实现一套企业智能客服系统

大型语言模型&#xff08;LLM&#xff09;相较于传统的语言模型具有更强大的能力&#xff0c;然而在某些情况下&#xff0c;它们仍可能无法提供准确的答案。为了解决大型语言模型在生成文本时面临的一系列挑战&#xff0c;提高模型的性能和输出质量&#xff0c;研究人员提出了一…

软件测试面试必杀篇:【2024软件测试面试八股文宝典】

800道软件测试面试真题&#xff0c;高清打印版打包带走&#xff0c;横扫软件测试面试高频问题&#xff0c;涵盖测试理论、Linux、MySQL、Web测试、接口测试、App测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块面试题&am…

ssm三农产品助推网站-计算机毕业设计源码91990

目录 摘要 1 绪论 1.1选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2网站分析 2.1 可行性分析 2.2 网站流程分析 2.2.1 数据流程 2.2.2 业务流程 2.3 网站功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 网站用例分析 2.5本章小结 3 网站总体设…

怎么在线打开AI文件?推荐使用这款免费白板软件!

在我们的日常生活和工作中&#xff0c;AI文件的使用频率越来越高。但是&#xff0c;对于许多非设计从业者来说&#xff0c;如何打开AI文件仍然是一个经常遇到的问题。 别担心&#xff0c;免费的在线白板软件就是你的解决方案。这种工具不仅可以轻松打开AI文件&#xff0c;还可…

AI 与数据的智能融合丨大模型时代下的存储系统

WOT 全球技术创新大会2024北京站于 6 月 22 日圆满落幕。本届大会以“智启新纪&#xff0c;慧创万物”为主题&#xff0c;邀请到 60 位不同行业的专家&#xff0c;聚焦 AIGC、领导力、研发效能、架构演进、大数据等热门技术话题进行分享。 近年来&#xff0c;数据和人工智能已…

springboot+vue+mybatis前台点菜系统+PPT+论文+讲解+售后

21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息存储达到…

【操作系统】进程管理——调度基础(个人笔记)

学习日期&#xff1a;2024.7.3 内容摘要&#xff1a;调度的概念、层次&#xff0c;进程调度的时机&#xff0c;调度器和闲逛进程&#xff0c;调度算法的评价指标 调度的基本概念 有一堆任务需要处理&#xff0c;但由于资源有限&#xff0c;有的事情不能同时处理&#xff0c;这…

virtualbox+Ubuntu部分窗口显示错乱

如下图&#xff1a; 窗口标题显示错乱&#xff0c;跟一般乱码不一样。 解决办法&#xff1a; 在virtualbox设置中&#xff0c;显示选项卡&#xff0c;取消勾选启用3D加速 也可参考此链接&#xff1a;linux ubuntu 中vscode中央窗口显示出现异常/显示错误_开发工具-CSDN问答

替换数据库是换肤还是换心?

上周末参加了自主可控数据库的沙龙。在会上我进行了主题演讲《围追堵截下&#xff0c;Oracle还能在国内立足么》 先听结论吧 我个人认为在很长一段时间还是你可以立足的。IDC最近公布的数据如下。本地部署中&#xff0c;Oracle居然是第一位的。这个数据是超出我想象的。去O都…

【机器学习】Datawhale-AI夏令营分子性质AI预测挑战赛

参赛链接&#xff1a;零基础入门 Ai 数据挖掘竞赛-速通 Baseline - 飞桨AI Studio星河社区 一、赛事背景 在当今科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的深度和广度渗透到科研领域&#xff0c;特别是在化学及药物研发中展现出了巨…

[我靠升级逆袭成为大师]韩漫日漫无删减完整版,免费在线观看漫画

[我靠升级逆袭成为大师]韩漫日漫无删减完整版&#xff0c;免费在线观看漫画 不能多说&#xff0c;怕审-核不过&#xff0c;自己看图吧。 目前统计【统计日期&#xff1a;2024-07-03】&#xff1a; 完结的有&#xff1a;420部。 连载的有&#xff1a;308部&#xff0c;持续更…

关于工时表软件,知道这四点就够了

在当今商业环境日益加快的节奏中&#xff0c;分秒必争。对于企业而言&#xff0c;了解内部时间的使用情况是确保效率、优化资源分配和提高生产力的关键。工时表在这里发挥着不可或缺的作用&#xff0c;它不仅是行政工作的组成部分&#xff0c;更是明确运营、加强项目管理和简化…

程序员的加油站,各类技术文章,可视化技术,在线源码资源,在线实用工具,数据爬虫接口持续集成更新中

先挂网址&#xff1a;https://wheart.cn 可视化大屏模板与设计&#xff0c;在线预览 上百例可视化模板 技术文章、资源下载等各类资源导航页 echart在线实用demo 各种在线工具提升开发效率 echart在线代码模板

Raylib 坐标系适应与GPU绘制参数

通过750 - 鼠标坐标&#xff0c;把原点在左上角的鼠标坐标变成左下角 实现输入数据后的坐标系同GPU原点在左下角坐标相同&#xff0c; 比数组0&#xff0c;0对应左上角好&#xff0c; 此时实际上数组0&#xff0c;0对应左下角 #include <raylib.h> // 感受&#xff1a…