如何关闭/清除 IPC 消息队列?

Posted

技术标签:

【中文标题】如何关闭/清除 IPC 消息队列?【英文标题】:How to close/clear an IPC message queue? 【发布时间】:2021-12-07 09:13:48 【问题描述】:

我在 process_B 的主线程的清理中有这个调用,它接收 IPC 消息队列上的消息:

if (msgctl(qId, IPC_RMID, NULL) < 0) 
    perror("msgctl");

到达时,报告以下内容:

msgctl : Invalid argument
Error: failed to remove message queue.

我有另一个进程_A,它向进程_B 发送消息并且没有被关闭。

那么man msgctl里面就有这个说法……

    IPC_RMID
              Immediately remove the  message  queue,  awakening  all  waiting
              reader  and writer processes (with an error return and errno set
              to EIDRM).  The calling process must have appropriate privileges
              or  its  effective user ID must be either that of the creator or
              owner of the message queue.  The third argument to  msgctl()  is
              ignored in this case.

我不清楚删除消息队列如何唤醒所有读者和作者。 process_A 是否也必须以某种方式关闭,然后 process_B 才能删除消息队列?

如果 process_B 关闭,我正在尝试清理资源以包含此消息队列。如果它重新启动,我希望 process_B 在清除队列后“重新连接”到消息队列,以防 process_A 从未关闭。可以清除队列吗?然后我当然会为 process_A 做同样的事情。

更新:(增加消息队列的开启):

    key_t key = ftok(".", 'm');

    int qid = msgget(key, IPC_CREAT | 0644);
    
    if (qid == -1) 
        perror("msgget");

        return -1;
    

【问题讨论】:

你能说明你是如何打开你的消息队列的吗? 添加了开头。两个进程之间消息发送成功。 qid 是否在您调用(msgctl(qId, IPC_RMID, NULL) 的范围内? 【参考方案1】:

我在 process_B 的主线程的清理中有这个调用 在 IPC 消息队列上接收消息:

if (msgctl(qId, IPC_RMID, NULL) < 0) 
    perror("msgctl");

到达时,报告以下内容:

msgctl : Invalid argument
Error: failed to remove message queue.

“错误:”消息必须来自其他没有证据的代码,但“msgctl:”消息似乎是从perror() 输出的,报告EINVAL。对于IPC_RMID 命令,表示传递给函数的队列 ID 无效。也许那个队列已经被删除了?

我不清楚删除消息队列如何唤醒所有读者和作者。 process_A 是否也必须以某种方式关闭,然后 process_B 才能删除消息队列?

删除队列会唤醒所有等待的读取器和写入器。也就是说,当前被阻止尝试向队列发送消息或从中接收消息的那些。文档只是说这些调用将停止阻塞,而是在errno 设置为EIDRM 时失败(返回-1)。所以不,process_A 不必在 process_B 移除队列之前终止或执行任何其他操作。

然而,

如果 process_B 关闭,我正在尝试清理要包含的资源 这个消息队列。

到目前为止还可以。

如果重新启动,我希望 process_B 能够 在清除队列中的队列后“重新连接”到消息队列 情况下 process_A 从未关闭。

我认为您没有理解移除队列意味着什么。成功删除它后,没有任何东西可以重新连接。相反,您必须创建一个新队列,并以某种方式让所有相关进程附加到并使用该队列。它很可能有不同的队列 ID(尽管通过相同的密钥获得)。

正在清除队列 可能的?然后我当然会为 process_A 做同样的事情。

您可以通过阻止所有进程发送新消息(通过进程共享的互斥锁或信号量)然后接收所有可用消息来清除队列而不删除它。不要忘记提供要释放的互斥锁/信号量。

但是,我敦促您在此处考虑您的策略。如果您只是清除队列而不删除它,那么没有什么可以阻止 process_A 在没有 process_B 运行时向队列发送更多消息,所以

    清除队列实际上对资源使用没有太大作用,并且 您需要考虑新进程_B 将如何处理在开始执行之前发送的消息。

反向同样适用。

另外,请记住 System V 消息队列具有内核持久性,因此它们的生命周期与任何特定进程的生命周期无关。 SysV MQ 将从创建到显式删除,或直到系统关闭,以先到者为准。

【讨论】:

以上是关于如何关闭/清除 IPC 消息队列?的主要内容,如果未能解决你的问题,请参考以下文章

IPC - 消息队列(Message Queue)- 使用

IPC - 消息队列(Message Queue)- 使用

IPC - 消息队列(Message Queue)- 使用

IPC - 消息队列(Message Queue)- 使用

检查 IPC 消息队列是不是已经存在而不创建它

如何清空Windows消息队列