2022年2022年进程通信之消息队列 .pdf

上传人:C****o 文档编号:39899513 上传时间:2022-09-08 格式:PDF 页数:6 大小:50.58KB
返回 下载 相关 举报
2022年2022年进程通信之消息队列 .pdf_第1页
第1页 / 共6页
2022年2022年进程通信之消息队列 .pdf_第2页
第2页 / 共6页
点击查看更多>>
资源描述

《2022年2022年进程通信之消息队列 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年进程通信之消息队列 .pdf(6页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、进程间通信之消息队列消息队列现在我们来讨论第三种也是最后一种System V IPV 工具:消息队列。在许多方面看来,消息队列类似于有名管道,但是却没有与打开与关闭管道的复杂关联。然而,使用消息队列并没有解决我们使用有名管道所遇到的问题,例如管道上的阻塞。消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法。与有名管道比较起来,消息队列的优点在独立于发送与接收进程,这减少了在打开与关闭有名管道之间同步的困难。消息队列提供了一种由一个进程向另一个进程发送块数据的方法。另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块。消息队列的好处在于我们几乎可以完全避免

2、同步问题,并且可以通过发送消息屏蔽有名管道的问题。更好的是,我们可以使用某些紧急方式发送消息。坏处在于,与管道类似,在每一个数据块上有一个最大尺寸限制,同时在系统中所有消息队列上的块尺寸上也有一个最大尺寸限制。尽管有这些限制,但是X/Open 规范并没有定义这些限制的具体值,除了指出超过这些尺寸是某些消息队列功能失败的原因。Linux 系统有两个定义,MSGMAX与 MSGMNB,这分别定义单个消息与一个队列的最大尺寸。这些宏定义在其他系统上也许并不相同,甚至也许就不存在。消息队列函数定义如下:#include int msgctl(int msqid,int cmd,struct msqid

3、_ds*buf);int msgget(key_t key,int msgflg);int msgrcv(int msqid,void*msg_ptr,size_t msg_sz,long int msgtype,int msgflg);int msgsnd(int msqid,const void*msg_ptr,size_t msg_sz,int msgflg);与信息号和共享内存一样,头文件sys/types.h与 sys/ipc.h 通常也是需要的。Msgget()我们可以使用msgget函数创建与访问一个消息队列:int msgget(key_t key,int msgflg);与其

4、他IPC 工具类似,程序必须提供一个指定一个特定消息队列的key 值。特殊值IPC_PRIV ATE 创建一个私有队列,这在理论上只可以为当前进程所访问。与信息量和共享内存一样,在某些Linux 系统上,消息队列并不是私有的。因为私有队列用处较少,因而这并不是一个严重问题。与前面一样,第二个参数,msgflg,由 9 个权限标记组成。要创建一个新的消息队列,由 IPC_CREAT 特殊位必须与其他的权限位进行或操作。设置 IPC_CREAT标记与指定一个已存在的消息队列并不是错误。如果消息队列已经存在,IPC_CREAT 标记只是简单的被忽略。如果成功,msgget 函数会返回一个正数作为队列

5、标识符,如果失败则会返回-1。Msgsnd()名师资料总结-精品资料欢迎下载-名师精心整理-第 1 页,共 6 页 -msgsnd函数允许我们将消息添加到消息队列:int msgsnd(int msqid,const void*msg_ptr,size_t msg_sz,int msgflg);消息结构由两种方式来限定。第一,他必须小于系统限制,第二,必须以 long int 开始,这在接收函数中会用作一个消息类型。当我们在使用消息时,最好是以如下形式来定义我们的消息结构:struct my_message long int message_type;/*The data you wish t

6、o transfer*/因为 message_type 用于消息接收,所以我们不能简单的忽略他。我们必须定义我们自己的数据结构来包含并对其进行初始化,从而他可以包含一个可知的值。第一个参数,msgid,是由 msgget函数所返回的消息队列标识符。第二个参数,msg_ptr,是一个指向要发送消息的指针,正如前面所描述的,这个消息必须以 long int 类型开始。第三个参数,msg_sz,是由 msg_ptr 所指向的消息的尺寸。这个尺寸必须不包含long int 消息类型。第四个参数,msgflg,控制如果当前消息队列已满或是达到了队列消息的系统限制时如何处理。如果msgflg 标记设置了I

7、PC_NOWAIT,函数就会立即返回而不发送消息,并且返回值为-1。如果 msgflg 标记清除了IPC_NOWAIT 标记,发送进程就会被挂起,等待队列中有可用的空间。如果成功,函数会返回0,如果失败,则会返回-1。如果调用成功,系统就会复杂一份消息数据并将其放入消息队列中。Msgrcv()msgrcv 函数由一个消息队列中收取消息:int msgrcv(int msqid,void*msg_ptr,size_t msg_sz,long int msgtype,int msgflg);第一个参数,msqid,是由 msgget函数所返回的消息队列标记符。第二个参数,msg_ptr,是一个指向

8、将要接收消息的指针,正如在msgsnd 函数中所描述的,这个消息必须以long int 类型开始。第三个参数,msg_sz,是由 msg_ptr 所指向的消息的尺寸,并不包含long int 消息类型。第四个参数,msgtype,是一个 long int 类型,允许一个接收优先级形式的实现。如果 msgtype的值为 0,队列中第一个可用的消息就会被接收。如果其值大于0,具有相同消息类型的第一个消息就会被接收。如果其值小于0,第一个具有相同类型或是小于msgtype 绝对值的消息就会被接收。这听起来要比实际操作复杂得多。如果我们只是简单的希望以其发送的顺序来接收消息,我们可以将msgtype

9、设置为0。如果我们希望接收特殊消息类型的消息,我们可以将msgtype 设置为等于这个值。如果我们希望接收消息类型为n 或是小于n 的值,我们可以将msgtype 设置为-n。名师资料总结-精品资料欢迎下载-名师精心整理-第 2 页,共 6 页 -第五个参数,msgflg,控制当没有合适类型的消息正在等待被接收时如何处理。如果在 msgflg中设置了 IPC_NOWAIT位,调用就会立即返回,而返回值为-1。如果 msgflg 标记中消除了IPC_NOWAIT 位,进程就会被挂起,等待一个合适类型的消息到来。如果成功,msgrcv 会返回放入接收缓冲区中的字节数,消息会被拷贝到由msg_ptr

10、 所指向的用户分配缓冲区中,而数据就会由消息队列中删除。如果失败则会返回-1。Msgctl()最后一个消息队列函数是msgctl,这与共享内存中的控制函数十分类型。int msgctl(int msqid,int command,struct msqid_ds*buf);msqid_ds 结构至少包含下列成员:struct msqid_ds uid_t msg_perm.uid;uid_t msg_perm.gid mode_t msg_perm.mode;第一个参数,msqid,是由 msgget函数所返回的标记符。第二个参数,command,是要执行的动作。他可以取下面三个值:命令描述 I

11、PC_STAT 设置 msqid_ds 结构中的数据来反射与消息队列相关联的值。IPC_SET 如果进程有权限这样做,这个命令会设置与msqid_ds 数据结构中所提供的消息队列相关联的值。IPC_RMID 删除消息队列。如果成功则会返回0,如果失败则会返回-1。当进程正在msgsnd 或是 msgrcv 函数中等待时如果消息队列被删除,发送或接收函数就会失败。试验消息队列现在我们已经了解了消息队列的定义,我们可以来看一下他们是如何实际工作的。与前面一样,我们将会编写两个程序:msg1.c 来接收,msg2.c 来发送。我们会允许任意一个程序创建消息队列,但是使用接收者在接收到最后一条消息后删

12、除消息队列。1 下面是接收程序:#include#include#include#include#include#include#include#include struct my_msg_st 名师资料总结-精品资料欢迎下载-名师精心整理-第 3 页,共 6 页 -long int my_msg_type;char some_textBUFSIZ;int main()int running=1;int msgid;struct my_msg_st some_data;long int msg_to_receive=0;2 首先,我们设置消息队列:msgid=msgget(key_t)1234

13、,0666|IPC_CREAT);if(msgid=-1)fprintf(stderr,msgget failed with error:%dn,errno);exit(EXIT_FAILURE);3 然后,接收消息队列中的消息直到遇到一个end 消息。最后,消息队列被删除:while(running)if(msgrcv(msgid,(void*)&some_data,BUFSIZ,msg_to_receive,0)=-1)fprintf(stderr,msgrcv failed with errno:%dn,errno);exit(EXIT_FAILURE);printf(You wrote

14、:%s,some_data.some_text);if(strncmp(some_data.some_text,end,3)=0)running=0;if(msgctl(msgid,IPC_RMID,0)=-1)fprintf(stderr,msgctl(IPC_RMID)failedn);exit(EXIT_FAILURE);名师资料总结-精品资料欢迎下载-名师精心整理-第 4 页,共 6 页 -exit(EXIT_SUCCESS);4 发 送 程 序 与msg1.c 类 似。在main函 数 中,删 除msg_to_receive声 明,代 之 以bufferBUFSIZ。移除消息队列删除

15、代码,并且在running 循环中做出如下更改。现在我们调用msgsnd 来将输入的文本发送到队列中。#include#include#include#include#include#include#include#include#define MAX_TEXT 512 struct my_msg_st long int my_msg_type;char some_textMAX_TEXT;int main()int running=1;struct my_msg_st some_data;int msgid;char bufferBUFSIZ;msgid=msgget(key_t)1234,

16、0666|IPC_CREAT);if(msgid=-1)fprintf(stderr,msgget failed with errno:%dn,errno);exit(EXIT_FAILURE);while(running)名师资料总结-精品资料欢迎下载-名师精心整理-第 5 页,共 6 页 -printf(Enter some text:);fgets(buffer,BUFSIZ,stdin);some_data.my_msg_type=1;strcpy(some_data.some_text,buffer);if(msgsnd(msgid,(void*)&some_data,MAX_TEX

17、T,0)=-1)fprintf(stderr,msgsnd failedn);exit(EXIT_FAILURE);if(strncmp(buffer,end,3)=0)running=0;exit(EXIT_SUCCESS);与管道中的例子不同,进程并没有必要提供自己的同步机制。这是消息队列比起管道的一个巨大优点。假设消息队列有空间,发送者可以创建队列,在队列中放入一些数据,并且甚至可以在接收者启动之前退出。我们会首先运行发送者。如下面的例子输出:$./msg2 Enter some text:hello Enter some text:How are you today?Enter some text:end$./msg1 You wrote:hello You wrote:How are you today?You wrote:end$工作原理发送者程序使用msgget 创建一个消息队列;然后使用msgsnd函数向队列中添加消息。接收者使用msgget 来获得消息队列标识符,并且接收消息,直到接收到特殊消息end。然后他会使用msgctl 删除消息队列进行一些清理工作。名师资料总结-精品资料欢迎下载-名师精心整理-第 6 页,共 6 页 -

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁