前言

接下讨论的IPC机制,它们最初由System V版本的Unix引入。由于这些机制都出现在同一个版本中并且有着相似的编程接口,所以它们被称为System V IPC机制。接下来的内容包括:

信号量:用于管理对资源的访问。

共享内存:用于在程序之间高效地共享数据。

消息队列:在程序之间传递数据。

操作系统中的同步和异步:https://blog.csdn.net/qq_38289815/article/details/81012826

进程间通信:管道和命名管道(FIFO)  https://blog.csdn.net/qq_38289815/article/details/104742682

进程间通信:信号量  https://blog.csdn.net/qq_38289815/article/details/104762940

进程间通信:共享内存  https://blog.csdn.net/qq_38289815/article/details/104776076

消息队列

消息队列与命名管道有许多相似之处,但少了在打开和关闭管道方面的复杂性。但使用消息队列并未解决我们在使用命名管道时遇到的一些问题,如管道满时的阻塞问题。消息队列提供了一种在两个不相关的进程之间传递数据的简单且有效的方法。与命名管道相比,消息队列的优势在于,它独立于发送和接收进程而存在,这消除了在同步命名管道的打开和关闭时可能产生的一些困难。

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。优点:我们可以通过发送消息来避免命名管道的同步和阻塞问题;可以用一些方法来提前查看紧急消息。缺点:消息队列与命名管道一样,每个数据块都有一个最大长度的限制,系统中所有队列所包含的全部数据块的总长度也有一个上限。Linux系统用宏定义MSGMAX和MSGMNB来表示一条消息的最大长度和一个队列的最大长度。

消息队列函数的定义如下:

#include <sys/msg.h>int msgctl(int msgid, int cmd, struct msgid_ds *buf);
int msgget(key_t key, int msgflg);
int msgrcv(int msgid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

msgget()函数

msgget函数用来创建和访问一个消息队列。它的原型为:

int msgget(key_t, key, int msgflg);
成功时返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1。

与其他的IPC机制一样,程序必须提供一个键来命名某个特定的消息队列。msgflg是一个权限标志,表示消息队列的访问权限,它与文件的访问权限一样。msgflg可以与IPC_CREAT做或操作,表示当key所命名的消息队列不存在时创建一个消息队列,如果key所命名的消息队列存在时,IPC_CREAT标志会被忽略,而只返回一个标识符。

msgsnd()函数

msgsnd函数用来把消息添加到消息队列中。它的原型为:

int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
成功时函数返回0,失败时返回-1。如果调用成功,消息数据的一份副本将被放到消息队列中。

msgid是由msgget函数返回的消息队列标识符。

msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体(还有长度必须小于系统规定的上限),接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:

struct my_message {long int message_type;/* The data you wish to transfer */
};

msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。
msgflg 用于控制在消息队列满或队列消息达到系统范围的限制时将要发生的事情。如果msgflg中设置IPC_NOWAIT状态,函数将立刻返回,不发送消息并且返回值为-1。如果msgflg中IPC_NOWAIT标志被清除,则发送进程将挂起以等待队列中腾出可用空间。

msgrcv()

msgrcv函数用来从一个消息队列获取消息,它的原型为:

int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1。

msgid, msg_ptr, msg_st 的作用和函数msgsnd函数的一样。

msgtype 可以实现一种简单的接收优先级。如果msgtype的值为0,就获取队列中的第一个可用消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。

msgflg 用于控制当队列中没有相应类型的消息可以接收时将发生的事情。如果msgflg中设置IPC_NOWAIT状态,函数将立刻返回,返回值为-1。如果msgflg中IPC_NOWAIT标志被清除,则发送进程将挂起以等待队列中腾出可用空间。

msgctl()

msgctl函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:

int msgctl(int msgid, int command, struct msgid_ds *buf);
成功时返回0,失败时返回-1。

msgid是由msgget返回的消息队列标识符。

command是将要采取的动作,它可以取3个值:

IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。

IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值

IPC_RMID:删除消息队列

buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:

struct msgid_ds
{uid_t shm_perm.uid;uid_t shm_perm.gid;mode_t shm_perm.mode;
};

使用消息队列完成进程间通信

由于可以让不相关的进程完成通信,所以我们在这里将编写两个程序,msg1.c用于接收消息,msg2.c用于发送消息。允许两个程序都可以创建消息队列,但只有接收者在接收完最后一个消息之后删除它。

#include <stdio.h>  //msg1.c
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <errno.h>struct msg_st
{long int my_msg_type;char text[BUFSIZ];
};int main(int argc, char **argv)
{int msgid;struct msg_st data;long int msg_to_receive = 0;   // 建立消息队列msgid = msgget((key_t)1234, 0666 | IPC_CREAT);if (msgid == -1){fprintf(stderr, "msgget failed width error: %d\n", errno);exit(EXIT_FAILURE);}// 从队列中获取消息,直到遇到end消息为止while (1){if (msgrcv(msgid, (void *)&data, BUFSIZ, msg_to_receive, 0) == -1){fprintf(stderr, "msgrcv failed width erro: %d", errno);}printf("You wrote: %s", data.text);// 遇到end结束if (strncmp(data.text, "end", 3) == 0){break;}}// 删除消息队列if (msgctl(msgid, IPC_RMID, 0) == -1){fprintf(stderr, "msgctl(IPC_RMID) failed\n");}exit(EXIT_SUCCESS);
}
#include <stdlib.h>  //msg2.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <errno.h>#define MAX_TEXT 512struct msg_st
{long int my_msg_type;char text[MAX_TEXT];
};int main(int argc, char **argv)
{struct msg_st data;char buffer[BUFSIZ];int msgid = -1;// 建立消息队列msgid = msgget((key_t)1234, 0666 | IPC_CREAT);if (msgid == -1){fprintf(stderr, "msgget failed error: %d\n", errno);exit(EXIT_FAILURE);}// 向消息队里中写消息,直到写入endwhile (1){printf("Enter some text: \n");fgets(buffer, BUFSIZ, stdin);data.my_msg_type = 1; strcpy(data.text, buffer);// 向队列里发送数据if (msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1){fprintf(stderr, "msgsnd failed\n");exit(EXIT_FAILURE);}// 输入end结束输入if (strncmp(buffer, "end", 3) == 0){break;}sleep(1);}exit(EXIT_SUCCESS);
}

实验解析

发送者程序通过msgget来创建一个消息队列,然后用msgsnd向队列中增加消息。接收者用msgget获得消息队列标识符,然后开始接收消息,直到接收到特殊的“end”为止。然后它用msgctl来删除消息队列以完成清理工作。

进程间通信:消息队列概念及代码相关推荐

  1. Linux的进程间通信-消息队列

    Linux的进程间通信-消息队列 微博ID:orroz 微信公众号:Linux系统技术 前言 Linux系统给我们提供了一种可以发送格式化数据流的通信手段,这就是消息队列.使用消息队列无疑在某些场景的 ...

  2. Linux进程间通信--消息队列(Message queuing)

    今天我们来谈一谈Linux进程间通信的方式之一消息队列 我们先来看看关于消息队列的定义: 1.消息队列是消息的链表,存放在内核中并由消息队列标识符表示. 2.消息队列提供了一个从一个进程向另一个进程发 ...

  3. 进程间通信——消息队列(Message queue)

    在Linux中,IPC消息队列是一个双向通信的全内存设计,即内核保证了读写顺序和数据同步,并且是性能比较好的先进先出的数据结构.消息队列的应用场景:比如异步任务处理,抢占式的数据分发,顺序缓存区等. ...

  4. linux进程间通信--消息队列相关函数(ftok)详解

    ftok 消息队列.信号灯.共享内存常用在Linux服务端编程的进程间通信环境中.而此三类编程函数在实际项目中都是用System V IPC函数实现的.System V IPC函数名称和说明如下表15 ...

  5. 【Linux系统编程】进程间通信--消息队列

    概述 消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法,其特点如下: 1)消息队列可以实现消息的随机查询.消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取. 2)消息队列允 ...

  6. rabbitmq 消费端代码获取队列名称_C#调用RabbitMQ实现消息队列的示例代码

    前言 我在刚接触使用中间件的时候,发现,中间件的使用并不是最难的,反而是中间件的下载,安装,配置才是最难的. 所以,这篇文章我们从头开始学习RabbitMq,真正的从头开始. 关于消息队列 其实消息队 ...

  7. Linux学习笔记-消息队列概念

    目录 System V IPC概念 System V IPC对象的访问 举几个例子 IPC对象的权限和所有者结构体 消息队列 消息队列属性 System V IPC概念 Unix系统存在信号.管道和命 ...

  8. 【进程】进程间通信----消息队列

    文章目录 1.消息队列 2.特性 3.实现接口 4.消息队列进程间通信 5.消息队列和命名管道的区别 5.1 相同之处 5.2 消息队列的优势 6.消息队列组织图 1.消息队列 消息队列,就是一个消息 ...

  9. qt使用消息队列服务器,qt代码实现消息队列通信

    qt代码实现消息队列通信 内容精选 换一换 模式介绍:命令模式(command)命令模式的解释如下:向对象发送一个请求,但是并不知道该请求的具体接收者是谁,具体的处理过程是如何的,只知道在程序运行中指 ...

最新文章

  1. qfile 创建文件_Qt之二进制文件读写
  2. 基于深度强化学习的区域化视觉导航方法​​
  3. html5 写json 文件,HTML5实现本地JSON文件的读写
  4. npm 编译打包vue_从零到一教你基于vue开发一个组件库
  5. MFC中打开指定文件夹并默认选中该文件夹中的某个文件
  6. 需求工程:加强监理,规避风险(转载)续三
  7. 2021-2025年中国单相静态电能表行业市场供需与战略研究报告
  8. 动态HTML事件(Event)小结
  9. mysql索引有几种_MySQL有哪些索引类型 ?
  10. Google常用搜索技巧
  11. PRM–endRequest事件
  12. FreeRTOS 入门
  13. C语言基础犄角旮旯的知识之数据类型
  14. HTML获取当前IP和当前位置
  15. Alfred Workflow教程与实例
  16. 比周黑鸭与绝味食品更早上市的煌上煌,为何掉队了?
  17. 图像的压缩算法--尺寸压缩、格式压缩和品质压缩
  18. 数据库八股文--藤原豆腐店自用
  19. MobPush创建推送
  20. Apple Watch 中国应用初体验:勇气可嘉,但缺乏存在感

热门文章

  1. API---有意思的API
  2. 在C++中使用Protocol Buffers
  3. 垃圾回收机制和菜单栏工具栏
  4. MPAI正式启动端到端的AI编码标准
  5. 【线上分享】快直播—超低延迟直播技术方案及应用
  6. 吴涛 :低延迟传输协议和新Codec将成为热点
  7. spark项目实战:电商分析平台之各个范围Session步长、访问时长占比统计(需求一)
  8. JVM之堆Heap体系概述
  9. WebRTC 那些常用的缩略词以及部分知识杂谈
  10. Linux 安装 FFmpeg