我正在尝试在标准C库中使用msgsnd和msgrcv系统调用,但是没有达到预期/期望的性能。
我的问题是,当我调用msgrcv时,它不会等待具有指定mtype(4)的消息。
我首先发送一个mtype为1的消息。想法是另一个进程然后会收到此消息并发回一个mtype为4的确认消息。从documentation,我希望&# 34;如果msgtyp大于零,则收到msgtyp类型的第一条消息"。
我还希望它等到消息类型为msgtyp的消息在队列中。
来自文档:
我的msgrcv函数不会等待。我在下面创建了一个最小,完整且可验证的示例。
(另请注意,我没有运行任何其他可能使用mtype = 1拦截此消息的伴随程序,并在测试此程序时发回另一条mtype = 4的消息)。
#include <sys/msg.h>
#include <iostream>
using namespace std;
int main() {
int qid = msgget(ftok(".",'u'), IPC_EXCL|IPC_CREAT|0600);
struct buf {
long mtype; // required
int message; // mesg content
};
buf msg;
int size = sizeof(msg)-sizeof(long);
msg.mtype = 1;
msgsnd(qid, (struct msgbuf *)&msg, size, 0); // sending
cout << msg.message << endl;
//Get acknowledgement from receiverA
msgrcv(qid, (struct msgbuf *)&msg, size, 4, 0); // read mesg
cout << msg.message << endl;
}
更新:
msgrcv函数返回的errno值为22(EINVAL),根据文档的含义&#34; MessageQueueID参数不是有效的消息队列标识符。&#34;
所以我继续检查我的msgget函数的errno值是什么。 msgget函数返回值17(EEXIST)。不知道如何处理这个但是msgget()的文档说,&#34;如果msgflg同时指定了IPC_CREAT和IPC_EXCL并且密钥已存在消息队列,那么msgget()将失败并且errno设置为EEXIST。&#34 ;
只是搞乱了msgget函数,如果我改变了第二个参数,在ftok函数中生成一个不同的标识符,它只能在我运行一次时运行,如果我尝试再运行它第二次相同的标识符,错误返回。 所以我想我的问题可以简化为:我如何获得我想要使用的消息队列的qid但是如果它已经存在则不尝试生成它?
答案 0 :(得分:1)
尝试在调用IPC_EXCL
时删除msgget
。
来自https://www.tldp.org/LDP/lpg/node34.html
<强> IPC_EXCL 强>
与 IPC_CREAT 一起使用时,如果队列已存在则失败。
答案 1 :(得分:1)
从手册页:
如果msgflg同时指定了IPC_CREAT和IPC_EXCL以及消息队列 已经存在key,然后msgget()失败,并将errno设置为EEXIST。
当我第一次尝试执行你的代码时,它在msgrcv()上被阻止,但是当我重新执行它时,它并没有。因为在下一次迭代中,msgget()失败了,EXIST和qid填充了-1。由于这个msgsnd()以及msgrcv()因无效参数而失败。
上述问题的解决方法是删除消息队列,在从测试程序返回之前使用msgctl()删除消息队列id,如下所示:
msgctl(qid,IPC_RMID,NULL);
建议:始终检查系统调用的返回值。
希望这会对你有所帮助。