消息队列
<wbr><wbr><wbr> 在UNIX的SystemV版本,AT&T引进了三种新形式的IPC功能(消息队列、信号量、以及共享内存)。但BSD版本的UNIX使用套接口作为主要的IPC形式。Linux系统同时支持这两个版本。<div> <span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用<strong><em><span style="color:#ff0000;">msgget()</span></em></strong></span></span> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 如果希望创建一个新的消息队列,或者希望存取一个已经存在的消息队列,你可以使用系统调用msgget()。</wbr></wbr></wbr></span></p> <p><wbr></wbr></p> <p><span style="font-family:Verdana;">系统调用:msgget();<br>原型:int msgget(key_t key, int msgflg);<br>返回值:如果成功,返回消息队列标识符<br>如果失败,则返回-1:errno=EACCESS(权限不允许)<br>EEXIST(队列已经存在,无法创建)<br>EIDRM(队列标志为删除)<br>ENOENT(队列不存在)<br>ENOMEM(创建队列时内存不够)<br>ENOSPC(超出最大队列限制)</span></p> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 系统调用msgget()中的第一个参数是关键字值(通常是由<em><strong>ftok()</strong></em>返回的)。然后此关键字值将会和其他已经存在于系统内核中的关键字值比较。这时,打开和存取操作是和参数msgflg中的内容相关的。<br>IPC_CREAT如果内核中没有此队列,则创建它。<br>IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。</wbr></wbr></wbr></span></p> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。<br>下面看一个打开和创建一个消息队列的例子:<br>int<wbr> open_queue(key_t keyval)<br>{<br><wbr><wbr><wbr> intqid;<br><wbr><wbr> if((qid=<strong><em><span style="color:#0000ff;">msgget</span></em></strong>(keyval, IPC_CREAT|0660))==-1)<br><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr> return(-1);<br><wbr><wbr> }<br><wbr><wbr> return(qid);<br>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span></p> <p><wbr></wbr></p> <p><span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用<em><strong><span style="color:#ff0000;">msgsnd()</span></strong></em></span></span></p> <p><wbr><wbr><wbr> 一旦我们得到了队列标识符,我们就可以在队列上执行我们希望的操作了。如果想要往队列中发送一条消息,你可以使用系统调用msgsnd():</wbr></wbr></wbr></p> <p>系统调用:msgsnd();<br>原型:int<wbr> msgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);<br>返回值:如果成功,0。<br>如果失败,-1:errno=EAGAIN(队列已满,并且使用了IPC_NOWAIT)<br>EACCES(没有写的权限)<br>EFAULT(msgp地址无效)<br>EIDRM(消息队列已经删除)<br>EINTR(当等待写操作时,收到一个信号)<br>EINVAL(无效的消息队列标识符,非正数的消息类型,或<br>者无效的消息长度)<br>ENOMEM(没有足够的内存复制消息缓冲区)</wbr></p> <p><wbr><wbr><wbr> 系统调用msgsnd()的第一个参数是消息队列标识符,它是由系统调用msgget返回的。第二个参数是msgp,是指向消息缓冲区的指针。参数msgsz中包含的是消息的字节大小,但不包括消息类型的长度(4个字节)。<br><wbr><wbr><wbr> 参数msgflg可以设置为0(此时为忽略此参数),或者使用IPC_NOWAIT。</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr> 如果消息队列已满,那么此消息则不会写入到消息队列中,控制将返回到调用进程中。如果没有指明,调用进程将会挂起,直到消息可以写入到队列中。<br><wbr><wbr><wbr> 下面是一个发送消息的程序:</wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int send_message(int qid, struct mymsgbuf *qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(structmymsgbuf)-sizeof(long);<br>if((result = <em><strong><span style="color:#ff0000;">msgsnd</span></strong></em>(qid, qbuf, length, 0))==-1)<br>{<br><wbr><wbr><wbr> return(-1);<br>}<br><wbr><wbr><wbr> return(result);<br>}</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用:<strong><em><span style="color:#ff0000;">msgrcv();</span></em></strong></span><br>原型:int msgrcv(intmsqid,structmsgbuf*msgp,intmsgsz,longmtype,intmsgflg);<br>返回值:如果成功,则返回复制到消息缓冲区的字节数。<br>如果失败,则返回-1:errno=E2BIG(消息的长度大于msgsz,没有MSG_NOERROR)<br>EACCES(没有读的权限)<br>EFAULT(msgp指向的地址是无效的)<br>EIDRM(队列已经被删除)<br>EINTR(被信号中断)<br>EINVAL(msgqid无效,或者msgsz小于0)<br>ENOMSG(使用IPC_NOWAIT,同时队列中的消息无法满足要求)</span></p> <p><wbr><wbr><wbr> 第一个参数用来指定将<strong><span style="color:#ff0000;">要读取消息的队列</span></strong>。第二个参数代表要<strong><span style="color:#0000ff;">存储消息的消息缓冲区</span></strong>的地址。第三个参数是消息缓冲区的长度,不包括mtype的长度,它可以按照如下的方法计算:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> msgsz=sizeof(struct mymsgbuf)-sizeof(long);<br><wbr><wbr><wbr> 第四个参数是要从消息队列中读取的消息的类型。如果此参数的值为0,那么队列中最长时间的一条消息将返回,而不论其类型是什么。<br>如果调用中使用了IPC_NOWAIT作为标志,那么当没有数据可以使用时,调用将把ENOMSG返回到调用进程中。否则,调用进程将会挂起,直到队列中的一条消息满足msgrcv()的参数要求。如果当客户端等待一条消息的时候队列为空,将会返回EIDRM。如果进程在等待消息的过程中捕捉到一个信号,则返回EINTR。<br><wbr><wbr><wbr> 下面就是一个从队列中读取消息的程序:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int read_message(int qid,long type,struct mymsgbuf*qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(struct<wbr> mymsgbuf)-sizeof(long);<br>if((result=msgrcv(qid,qbuf,length,type,0))==-1)<br>{<br>return(-1);<br>}<br>return(result);<br>}<br><wbr><wbr><wbr><strong><span style="color:#990000;">在成功地读取了一条消息以后,队列中的这条消息的入口将被删除</span></strong>。<br><wbr><wbr><wbr> 参数msgflg中的MSG_NOERROR位提供一种额外的用途。如果消息的实际长度大于msgsz,同时使用了MSG_NOERROR,那么消息将会被截断,只有与msgsz长度相等的消息返回。一般情况下,系统调用msgrcv()会返回-1,而这条消息将会继续保存在队列中。我们可以利用这个特点编制一个程序,利用这个程序可以查看消息队列的情况,看看符合我们条件的消息是否已经到来:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int<wbr> peek_message(int qid,long type)<br>{<br>int<wbr> result,length;<br>if((result=msgrcv(qid,NULL,0,type,IPC_NOWAIT))==-1)<br>{<br>if(errno==E2BIG)<br>return(TRUE);<br>}<br>return(FALSE);<br>}<br><wbr><wbr><wbr> 在上面的程序中,我们忽略了缓冲区的地址和长度。这样,系统调用将会失败。尽管如此,我们可以检查返回的E2BIG值,它说明符合条件的消息确实存在。</wbr></wbr></wbr></wbr></wbr></p> <p><wbr></wbr></p> <p><span style="FONT-SIZE: 20px">系统调用<strong><em><span style="color:#ff0000;">msgctl()</span></em></strong></span></p> <p><wbr><wbr><wbr> 下面我们继续讨论如何使用一个给定的消息队列的内部数据结构。我们可以使用系统调用msgctl ( )来控制对消息队列的操作。</wbr></wbr></wbr></p> <p>系统调用: msgctl( ) ;<br>调用原型: int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );<br>返回值: 0 ,如果成功。<br>- 1,如果失败:errno = EACCES (没有读的权限同时cmd 是IPC_STAT )<br>EFAULT (buf 指向的地址无效)<br>EIDRM (在读取中队列被删除)<br>EINVAL (msgqid无效, 或者msgsz 小于0 )<br>EPERM (IPC_SET或者IPC_RMID 命令被使用,但调用程序没有写的权限)<br>下面我们看一下可以使用的几个命令:<br>IPC_STAT<br>读取消息队列的数据结构msqid_ds,并将其存储在b u f指定的地址中。<br>IPC_SET<br>设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。<br>IPC_RMID<br>从系统内核中移走消息队列。<br><wbr><wbr><wbr> 我们在前面讨论过了消息队列的数据结构(msqid_ds)。系统内核中为系统中的每一个消息队列保存一个此数据结构的实例。通过使用IPC_STAT命令,我们可以得到一个此数据结构的副本。下面的程序就是实现此函数的过程:</wbr></wbr></wbr></p> <p>int get_queue_ds( int qid, struct msgqid_ds *qbuf )<br>{<br>if( msgctl( qid, IPC_STAT, qbuf) == -1)<br>{<br>return(-1);<br>}<br>return(0);<br>}</p> <p><wbr><wbr><wbr> 如果不能复制内部缓冲区,调用进程将返回-1。如果调用成功,则返回0。缓冲区中应该包括消息队列中的数据结构。<br><wbr><wbr><wbr> 消息队列中的数据结构中唯一可以改动的元素就是ipc_perm。它包括队列的存取权限和关于队列创建者和拥有者的信息。你可以改变用户的id、用户的组id以及消息队列的存取权限。<br><wbr><wbr><wbr> 下面是一个修改队列存取模式的程序:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int change_queue_mode(int qid, char *mode )<br>{<br>struct msqid_ds tmpbuf;<br>/* Retrieve a current copy of the internal data structure */<br>get_queue_ds( qid, &tmpbuf);<br>/* Change the permissions using an old trick */<br>sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);<br>/* Update the internal data structure */<br>if( msgctl( qid, IPC_SET, &tmpbuf) == -1)<br>{<br>return(-1);<br>}<br>return(<br>}</p> <p><wbr><wbr><wbr> 我们通过调用get_queue_ds来读取队列的内部数据结构。然后,我们调用sscanf( )修改数据结构msg_perm中的mode 成员的值。但直到调用msgctl()时,权限的改变才真正完成。在这里msgctl()使用的是IPC_SET命令。<br><wbr><wbr><wbr> 最后,我们使用系统调用msgctl ( )中的IPC_RMID命令删除消息队列:</wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int remove_queue(int qid )<br>{<br>if( msgctl( qid, IPC_RMID, 0) == -1)<br>{<br>return(-1);<br>}<br>return(0);<br>}<br>};</p> </div></wbr></wbr></wbr>
<wbr><wbr><wbr> 在UNIX的SystemV版本,AT&T引进了三种新形式的IPC功能(消息队列、信号量、以及共享内存)。但BSD版本的UNIX使用套接口作为主要的IPC形式。Linux系统同时支持这两个版本。<div> <span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用<strong><em><span style="color:#ff0000;">msgget()</span></em></strong></span></span> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 如果希望创建一个新的消息队列,或者希望存取一个已经存在的消息队列,你可以使用系统调用msgget()。</wbr></wbr></wbr></span></p> <p><wbr></wbr></p> <p><span style="font-family:Verdana;">系统调用:msgget();<br>原型:int msgget(key_t key, int msgflg);<br>返回值:如果成功,返回消息队列标识符<br>如果失败,则返回-1:errno=EACCESS(权限不允许)<br>EEXIST(队列已经存在,无法创建)<br>EIDRM(队列标志为删除)<br>ENOENT(队列不存在)<br>ENOMEM(创建队列时内存不够)<br>ENOSPC(超出最大队列限制)</span></p> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 系统调用msgget()中的第一个参数是关键字值(通常是由<em><strong>ftok()</strong></em>返回的)。然后此关键字值将会和其他已经存在于系统内核中的关键字值比较。这时,打开和存取操作是和参数msgflg中的内容相关的。<br>IPC_CREAT如果内核中没有此队列,则创建它。<br>IPC_EXCL当和IPC_CREAT一起使用时,如果队列已经存在,则失败。</wbr></wbr></wbr></span></p> <p><span style="font-family:Verdana;"><wbr><wbr><wbr> 如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值的队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1。IPC_EXCL单独使用是没有用处的。<br>下面看一个打开和创建一个消息队列的例子:<br>int<wbr> open_queue(key_t keyval)<br>{<br><wbr><wbr><wbr> intqid;<br><wbr><wbr> if((qid=<strong><em><span style="color:#0000ff;">msgget</span></em></strong>(keyval, IPC_CREAT|0660))==-1)<br><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr> return(-1);<br><wbr><wbr> }<br><wbr><wbr> return(qid);<br>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></span></p> <p><wbr></wbr></p> <p><span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用<em><strong><span style="color:#ff0000;">msgsnd()</span></strong></em></span></span></p> <p><wbr><wbr><wbr> 一旦我们得到了队列标识符,我们就可以在队列上执行我们希望的操作了。如果想要往队列中发送一条消息,你可以使用系统调用msgsnd():</wbr></wbr></wbr></p> <p>系统调用:msgsnd();<br>原型:int<wbr> msgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg);<br>返回值:如果成功,0。<br>如果失败,-1:errno=EAGAIN(队列已满,并且使用了IPC_NOWAIT)<br>EACCES(没有写的权限)<br>EFAULT(msgp地址无效)<br>EIDRM(消息队列已经删除)<br>EINTR(当等待写操作时,收到一个信号)<br>EINVAL(无效的消息队列标识符,非正数的消息类型,或<br>者无效的消息长度)<br>ENOMEM(没有足够的内存复制消息缓冲区)</wbr></p> <p><wbr><wbr><wbr> 系统调用msgsnd()的第一个参数是消息队列标识符,它是由系统调用msgget返回的。第二个参数是msgp,是指向消息缓冲区的指针。参数msgsz中包含的是消息的字节大小,但不包括消息类型的长度(4个字节)。<br><wbr><wbr><wbr> 参数msgflg可以设置为0(此时为忽略此参数),或者使用IPC_NOWAIT。</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr> 如果消息队列已满,那么此消息则不会写入到消息队列中,控制将返回到调用进程中。如果没有指明,调用进程将会挂起,直到消息可以写入到队列中。<br><wbr><wbr><wbr> 下面是一个发送消息的程序:</wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int send_message(int qid, struct mymsgbuf *qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(structmymsgbuf)-sizeof(long);<br>if((result = <em><strong><span style="color:#ff0000;">msgsnd</span></strong></em>(qid, qbuf, length, 0))==-1)<br>{<br><wbr><wbr><wbr> return(-1);<br>}<br><wbr><wbr><wbr> return(result);<br>}</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><span style="font-family:Verdana;"><span style="FONT-SIZE: 20px">系统调用:<strong><em><span style="color:#ff0000;">msgrcv();</span></em></strong></span><br>原型:int msgrcv(intmsqid,structmsgbuf*msgp,intmsgsz,longmtype,intmsgflg);<br>返回值:如果成功,则返回复制到消息缓冲区的字节数。<br>如果失败,则返回-1:errno=E2BIG(消息的长度大于msgsz,没有MSG_NOERROR)<br>EACCES(没有读的权限)<br>EFAULT(msgp指向的地址是无效的)<br>EIDRM(队列已经被删除)<br>EINTR(被信号中断)<br>EINVAL(msgqid无效,或者msgsz小于0)<br>ENOMSG(使用IPC_NOWAIT,同时队列中的消息无法满足要求)</span></p> <p><wbr><wbr><wbr> 第一个参数用来指定将<strong><span style="color:#ff0000;">要读取消息的队列</span></strong>。第二个参数代表要<strong><span style="color:#0000ff;">存储消息的消息缓冲区</span></strong>的地址。第三个参数是消息缓冲区的长度,不包括mtype的长度,它可以按照如下的方法计算:<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> msgsz=sizeof(struct mymsgbuf)-sizeof(long);<br><wbr><wbr><wbr> 第四个参数是要从消息队列中读取的消息的类型。如果此参数的值为0,那么队列中最长时间的一条消息将返回,而不论其类型是什么。<br>如果调用中使用了IPC_NOWAIT作为标志,那么当没有数据可以使用时,调用将把ENOMSG返回到调用进程中。否则,调用进程将会挂起,直到队列中的一条消息满足msgrcv()的参数要求。如果当客户端等待一条消息的时候队列为空,将会返回EIDRM。如果进程在等待消息的过程中捕捉到一个信号,则返回EINTR。<br><wbr><wbr><wbr> 下面就是一个从队列中读取消息的程序:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int read_message(int qid,long type,struct mymsgbuf*qbuf)<br>{<br>intresult,length;<br>/*The length is essentially the size of the structure minus sizeof(mtype)*/<br>length=sizeof(struct<wbr> mymsgbuf)-sizeof(long);<br>if((result=msgrcv(qid,qbuf,length,type,0))==-1)<br>{<br>return(-1);<br>}<br>return(result);<br>}<br><wbr><wbr><wbr><strong><span style="color:#990000;">在成功地读取了一条消息以后,队列中的这条消息的入口将被删除</span></strong>。<br><wbr><wbr><wbr> 参数msgflg中的MSG_NOERROR位提供一种额外的用途。如果消息的实际长度大于msgsz,同时使用了MSG_NOERROR,那么消息将会被截断,只有与msgsz长度相等的消息返回。一般情况下,系统调用msgrcv()会返回-1,而这条消息将会继续保存在队列中。我们可以利用这个特点编制一个程序,利用这个程序可以查看消息队列的情况,看看符合我们条件的消息是否已经到来:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int<wbr> peek_message(int qid,long type)<br>{<br>int<wbr> result,length;<br>if((result=msgrcv(qid,NULL,0,type,IPC_NOWAIT))==-1)<br>{<br>if(errno==E2BIG)<br>return(TRUE);<br>}<br>return(FALSE);<br>}<br><wbr><wbr><wbr> 在上面的程序中,我们忽略了缓冲区的地址和长度。这样,系统调用将会失败。尽管如此,我们可以检查返回的E2BIG值,它说明符合条件的消息确实存在。</wbr></wbr></wbr></wbr></wbr></p> <p><wbr></wbr></p> <p><span style="FONT-SIZE: 20px">系统调用<strong><em><span style="color:#ff0000;">msgctl()</span></em></strong></span></p> <p><wbr><wbr><wbr> 下面我们继续讨论如何使用一个给定的消息队列的内部数据结构。我们可以使用系统调用msgctl ( )来控制对消息队列的操作。</wbr></wbr></wbr></p> <p>系统调用: msgctl( ) ;<br>调用原型: int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );<br>返回值: 0 ,如果成功。<br>- 1,如果失败:errno = EACCES (没有读的权限同时cmd 是IPC_STAT )<br>EFAULT (buf 指向的地址无效)<br>EIDRM (在读取中队列被删除)<br>EINVAL (msgqid无效, 或者msgsz 小于0 )<br>EPERM (IPC_SET或者IPC_RMID 命令被使用,但调用程序没有写的权限)<br>下面我们看一下可以使用的几个命令:<br>IPC_STAT<br>读取消息队列的数据结构msqid_ds,并将其存储在b u f指定的地址中。<br>IPC_SET<br>设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数。<br>IPC_RMID<br>从系统内核中移走消息队列。<br><wbr><wbr><wbr> 我们在前面讨论过了消息队列的数据结构(msqid_ds)。系统内核中为系统中的每一个消息队列保存一个此数据结构的实例。通过使用IPC_STAT命令,我们可以得到一个此数据结构的副本。下面的程序就是实现此函数的过程:</wbr></wbr></wbr></p> <p>int get_queue_ds( int qid, struct msgqid_ds *qbuf )<br>{<br>if( msgctl( qid, IPC_STAT, qbuf) == -1)<br>{<br>return(-1);<br>}<br>return(0);<br>}</p> <p><wbr><wbr><wbr> 如果不能复制内部缓冲区,调用进程将返回-1。如果调用成功,则返回0。缓冲区中应该包括消息队列中的数据结构。<br><wbr><wbr><wbr> 消息队列中的数据结构中唯一可以改动的元素就是ipc_perm。它包括队列的存取权限和关于队列创建者和拥有者的信息。你可以改变用户的id、用户的组id以及消息队列的存取权限。<br><wbr><wbr><wbr> 下面是一个修改队列存取模式的程序:</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int change_queue_mode(int qid, char *mode )<br>{<br>struct msqid_ds tmpbuf;<br>/* Retrieve a current copy of the internal data structure */<br>get_queue_ds( qid, &tmpbuf);<br>/* Change the permissions using an old trick */<br>sscanf(mode, "%ho", &tmpbuf.msg_perm.mode);<br>/* Update the internal data structure */<br>if( msgctl( qid, IPC_SET, &tmpbuf) == -1)<br>{<br>return(-1);<br>}<br>return(<br>}</p> <p><wbr><wbr><wbr> 我们通过调用get_queue_ds来读取队列的内部数据结构。然后,我们调用sscanf( )修改数据结构msg_perm中的mode 成员的值。但直到调用msgctl()时,权限的改变才真正完成。在这里msgctl()使用的是IPC_SET命令。<br><wbr><wbr><wbr> 最后,我们使用系统调用msgctl ( )中的IPC_RMID命令删除消息队列:</wbr></wbr></wbr></wbr></wbr></wbr></p> <p>int remove_queue(int qid )<br>{<br>if( msgctl( qid, IPC_RMID, 0) == -1)<br>{<br>return(-1);<br>}<br>return(0);<br>}<br>};</p> </div></wbr></wbr></wbr>