【问题标题】:How do I find waiting readers/writers for Linux System V Msg Queues?如何找到等待 Linux System V 消息队列的读取器/写入器?
【发布时间】:2017-02-09 12:45:16
【问题描述】:

我的任务是将一些使用 System V 队列的 C/C++ 代码从 HP-UX 移植到 Red Hat Linux (SVr4)。

大部分调用都翻译得很好,但我在一个特定问题上遇到了困难,因为它与在给定队列中发现等待的读者和作者有关。

在 HP 上,可以使用msgctl(IPC_STAT) 来获取包含给定队列详细信息的 msqid_ds 结构。

这个结构的细节中有一个短值msqid_ds.msg_perm.mode,它使用低9位来指定用户/组/其他的读/写权限。

但是,在 HP 上,高 7 位存储其他状态信息,其中包括两个标志后面的标志:

#define MSG_QWAIT       00001   /* a writer is waiting on qp->msg_cbytes */
#define MSG_FWAIT       00002   /* a writer is waiting on msgfp */

这允许人们测试,例如,(msqid.msg_perm.mode & (MSG_RWAIT | MSG_WWAIT)) 以查看队列中是否有读取器或写入器阻塞。

当我移植到 Linux 时,很明显这种能力是不一样的。这些标志的定义不存在,msqid_ds.msg_perm.mode 的值显然不存在高位信息。

但肯定存在维护这些队列的读取器和写入器的内核操作。我希望可以调用一些操作来发现这些信息。

【问题讨论】:

    标签: c linux sysv-ipc


    【解决方案1】:

    据我所知,Linux 没有面向用户的工具来获取您想要的信息。 POSIX 也没有定义任何这样的工具(甚至对于 POSIX 消息队列也没有定义)。当然,内核必须维护消息队列状态是对的,但我没有看到可以从用户空间查询该信息的现有机制。除非您喜欢为内核编写驱动程序,否则我认为您的移植需要进行比您希望的更深入的更改。

    但从长远来看,这不一定是坏事。调整您的代码,使其仅依赖于标准设施,而不是供应商扩展,可以预期使其更健壮、更易于维护和更便携。根据遗留代码试图做什么,您甚至可能最终在受影响的区域获得更好的设计。

    例如,考虑程序为什么需要相关信息,以及它将如何处理这些信息。我只看到一个很好的理由:测试是由进程/线程执行的,作为压力释放机制的一部分,如果队列被太多/太大的消息阻塞,一些消息将被丢弃。我考虑的所有其他原因要么是考虑不周,要么是通过使用非阻塞发送和/或接收来更好地​​服务。如果您的程序的原因属于后者,那么它有更好的方法来做它想做的事情。

    即使目的是上述压力释放,请注意,您获得的有关消息队列瞬态状态的任何信息都可能在程序获取之前就已经过时了。在您的程序对收集到的信息采取行动之前,所有被阻止的发件人可能已成功进行,并且新的邮件发送尝试可能已被阻止。这也许是一个可以理解的约束,但它应该为您的减压策略提供参考。在这种情况下,您至少有以下选择:

    • 与其尝试确定是否有任何发件人被阻止,不如确定队列是否已达到其容量。您可以从标准struct msqid_ds 确定当前和最大排队消息数。您还可以确定队列可以容纳的最大字节数,尽管没有标准方法来确定当前排队的字节数。 (但是,如果您仍然迷恋供应商扩展,则有一种特定于 Linux 的方法。)

    • 通过尝试向队列发送消息(使用非阻塞发送)来检查队列是否被阻塞。成功后,立即再次删除该消息。您可以使用消息类型将这些消息与应用程序的其他消息区分开来。在其他接收者的配合下,您或许可以使用消息类型来确保没有其他接收者收到这些探测消息。

    【讨论】:

    • 我正在处理的案例至少以两种方式使用信息。第一个是纯粹的信息。我们的用户可以“一目了然”地查看我们的数十个队列,其中一个行项目指示是否至少有一个进程在读/写操作中被阻塞。第二个是基本的固定机制。用户有一些基本操作允许他们截断队列内容或完全删除队列。这些选项很少使用(如果有的话);但如果有储物柜,有些是禁止的。你的结论强化了我得到的印象并且非常感激。
    • 顺便说一句,虽然我正在努力确定准确的 Linux 实现或版本,但我至少在过去 一些 中看到过 msqid_ds 的 wwait 和 rwait 成员的轶事信息Linux 版本。示例参考:tldp.org/LDP/lpg/node32.html 这让我很好奇它是否曾经存在于 Linux 中,但现在不再存在了。
    • LDP 节点似乎正在呈现内核的 internal 标头之一的版本。我不能确定是否有任何相应的用户空间标头曾经提供过您询问的信息,但他们肯定从未以 那种方式(即通过指向内部内核数据结构的指针)提供它,因为用户空间程序不能直接访问内核内存。
    • 另外请注意,编译面向用户的消息队列状态报告并不是我考虑并拒绝程序需要信息的可能原因之一。
    • 我突然想到,我将此答案标记为已接受,但从未跟进我实施的解决方案。最终,我使用 boost 进程间互斥体和共享内存来跟踪一对计数器,用于每个队列实例的读/写操作,从而解决了这个问题。这似乎满足了上述对面向用户的报告以及涉及的一两个其他次要检查的需求。
    猜你喜欢
    • 2013-03-29
    • 2010-12-15
    • 2011-12-12
    • 2020-04-18
    • 2017-05-21
    • 1970-01-01
    • 2011-09-18
    • 2011-05-05
    • 2010-09-28
    相关资源
    最近更新 更多