【发布时间】:2018-08-19 08:00:05
【问题描述】:
我正在尝试使用标准 C 库中的 msgsnd 和 msgrcv 系统调用,但没有获得预期/期望的性能。
我的问题是,当我调用 msgrcv 时,它并没有等待指定 mtype (4) 的消息。
我首先发送一条 mtype 为 1 的消息。这个想法是另一个进程将收到此消息并返回一个 mtype 为 4 的确认消息。从documentation,我希望“如果 msgtyp 是大于零,则接收到第一条 msgtyp 类型的消息”。
我还希望它等到消息类型为 msgtyp 的消息在队列中。
来自文档:
- 如果未在 msgflg 参数中设置 IPC_NOWAIT 标志,则调用线程会暂停处理,直到发生以下情况之一:
- 所需类型的消息被发送到消息队列。
- 消息队列标识符 msqid 已从系统中删除。发生这种情况时,msgrcv() 函数返回值 -1 并将 errno 设置为 EIDRM。
- 将信号传递给调用线程。发生这种情况时,msgrcv() 函数返回值 -1 并将 errno 设置为 EINTR。
我的 msgrcv 函数没有等待。我在下面创建了一个最小、完整且可验证的示例。
(另请注意,我没有运行任何其他可能会在测试此程序时拦截此消息并使用 mtype = 4 发送回另一条 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 函数返回 22 (EINVAL) 的 errno 值,根据文档,这意味着“MessageQueueID 参数不是有效的消息队列标识符。”
所以我继续检查我的 msgget 函数的 errno 值是什么。 msgget 函数返回值 17 (EEXIST)。不确定如何处理此问题,但 msgget() 的文档显示“如果 msgflg 同时指定 IPC_CREAT 和 IPC_EXCL,并且密钥的消息队列已经存在,则 msgget() 失败,errno 设置为 EEXIST。”
只是因为弄乱了 msgget 函数,如果我在 ftok 函数中更改第二个参数以生成不同的标识符,它会起作用,但只有当我运行一次时,如果我尝试使用相同的标识符,错误返回。 所以我想我的问题可以简化为:如何获取我想要使用的消息队列的 qid,但如果它已经存在则不尝试生成它?
【问题讨论】:
-
调用
msgrcv后能打印出errno的值吗? -
@MinhHoàng 更新了相关错误
标签: c++ message-queue system-calls