msgrcv 不等待带有错误号 22 (EINVAL) 的特定消息类型的消息
msgrcv not waiting for a message with a specific message type with errno 22 (EINVAL)
我正在尝试使用标准 C 库中的 msgsnd 和 msgrcv 系统调用,但没有获得 expected/desired 性能。
我的问题是,当我调用 msgrcv 时,它没有等待具有指定 mtype (4) 的消息。
我首先发送一条 mtype 为 1 的消息。我的想法是,另一个进程将收到此消息并发送回一条 mtype 为 4 的确认消息。从 documentation,我预计"if msgtyp is greater than zero, the first message of type msgtyp is received".
我还希望它等到消息类型为 msgtyp 的消息出现在队列中。
来自文档:
- 如果未在 msgflg 参数中设置 IPC_NOWAIT 标志,调用线程将暂停处理,直到发生以下情况之一:
- 所需类型的消息已发送到消息队列。
- 消息队列标识符 msqid 已从系统中删除。发生这种情况时,msgrcv() 函数 returns 的 return 值为 -1 且 errno 设置为 EIDRM。
- 一个信号被传送到调用线程。发生这种情况时,msgrcv() 函数 returns 的 return 值为 -1 且 errno 设置为 EINTR。
我的 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 函数 returning errno 值为 22 (EINVAL),根据文档,这意味着 "The MessageQueueID parameter is not a valid message queue identifier."
所以我继续检查我的 msgget 函数的 errno 值是多少。 msgget 函数 returns 的值为 17 (EEXIST)。不知道该怎么办,但是 msgget() 的文档说 "If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST."
如果我在 ftok 函数中更改 2nd 参数以生成不同的标识符,只是因为搞乱了 msgget 函数,它才有效,但只有当我 运行 它一次时,如果我尝试 运行 它第二次使用相同的标识符,错误 returns。
所以我想我的问题可以简化为:如何获取我想使用的消息队列的 qid,但如果它已经存在则不尝试生成它?
尝试在调用 msgget
时删除 IPC_EXCL
。
来自https://www.tldp.org/LDP/lpg/node34.html
IPC_EXCL
When used with IPC_CREAT, fail if queue already exists.
来自手册页:
If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue
already exists for key, then msgget() fails with errno set to EEXIST.
当我第一次尝试执行您的代码时,它在 msgrcv() 上阻塞了,但是当我 re-executed 时却没有。因为在下一次迭代中,msgget() 失败并返回 EXIST 并且 qid 填充为 -1。由于此 msgsnd() 以及 msgrcv() 因参数无效而失败。
上述问题的解决方案是删除消息队列,在从测试程序 returning 之前使用 msgctl() 删除消息队列 ID,如下所示:
msgctl(qid, IPC_RMID, NULL);
建议:始终检查 return 系统调用的值。
希望对您有所帮助。
我正在尝试使用标准 C 库中的 msgsnd 和 msgrcv 系统调用,但没有获得 expected/desired 性能。
我的问题是,当我调用 msgrcv 时,它没有等待具有指定 mtype (4) 的消息。
我首先发送一条 mtype 为 1 的消息。我的想法是,另一个进程将收到此消息并发送回一条 mtype 为 4 的确认消息。从 documentation,我预计"if msgtyp is greater than zero, the first message of type msgtyp is received".
我还希望它等到消息类型为 msgtyp 的消息出现在队列中。
来自文档:
- 如果未在 msgflg 参数中设置 IPC_NOWAIT 标志,调用线程将暂停处理,直到发生以下情况之一:
- 所需类型的消息已发送到消息队列。
- 消息队列标识符 msqid 已从系统中删除。发生这种情况时,msgrcv() 函数 returns 的 return 值为 -1 且 errno 设置为 EIDRM。
- 一个信号被传送到调用线程。发生这种情况时,msgrcv() 函数 returns 的 return 值为 -1 且 errno 设置为 EINTR。
我的 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 函数 returning errno 值为 22 (EINVAL),根据文档,这意味着 "The MessageQueueID parameter is not a valid message queue identifier."
所以我继续检查我的 msgget 函数的 errno 值是多少。 msgget 函数 returns 的值为 17 (EEXIST)。不知道该怎么办,但是 msgget() 的文档说 "If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST."
如果我在 ftok 函数中更改 2nd 参数以生成不同的标识符,只是因为搞乱了 msgget 函数,它才有效,但只有当我 运行 它一次时,如果我尝试 运行 它第二次使用相同的标识符,错误 returns。 所以我想我的问题可以简化为:如何获取我想使用的消息队列的 qid,但如果它已经存在则不尝试生成它?
尝试在调用 msgget
时删除 IPC_EXCL
。
来自https://www.tldp.org/LDP/lpg/node34.html
IPC_EXCL
When used with IPC_CREAT, fail if queue already exists.
来自手册页:
If msgflg specifies both IPC_CREAT and IPC_EXCL and a message queue already exists for key, then msgget() fails with errno set to EEXIST.
当我第一次尝试执行您的代码时,它在 msgrcv() 上阻塞了,但是当我 re-executed 时却没有。因为在下一次迭代中,msgget() 失败并返回 EXIST 并且 qid 填充为 -1。由于此 msgsnd() 以及 msgrcv() 因参数无效而失败。
上述问题的解决方案是删除消息队列,在从测试程序 returning 之前使用 msgctl() 删除消息队列 ID,如下所示:
msgctl(qid, IPC_RMID, NULL);
建议:始终检查 return 系统调用的值。
希望对您有所帮助。