POSIX 消息队列通过内核空间?

Posted

技术标签:

【中文标题】POSIX 消息队列通过内核空间?【英文标题】:POSIX Message Queue go through kernel space? 【发布时间】:2011-07-26 03:23:06 【问题描述】:

我希望在单进程多线程应用程序上使用 POSIX 消息队列。 mqueues 将用于在线程之间共享数据。

我对它们在 Linux 内核中的工作方式有些困惑。是否所有消息都通过内核空间,然后在接收时返回用户空间?又名从用户空间线程我执行 mq_send 并且消息最终在内核空间中,然后在接收它时是另一个系统调用以从内核空间获取消息。如果是这样,对于高使用率的消息队列来说,这不是非常低效吗?

【问题讨论】:

一个警告,比您更针对未来的读者:请注意 SysV IPC 对象(例如消息队列)是持久的。如果您的程序创建了一个但没有删除它,它将在程序退出后继续存在。将队列视为更像文件而不是套接字(只是更难管理,因为它们有 ID 而不是路径)。考虑在安装过程中而不是在执行过程中创建它们。 @Tom Anderson:POSIX 消息队列与 SysV 不同;它们也是持久的和类似的文件,但在 Linux 下,您可以挂载文件系统,查看它们并使用“rm”删除它们。 POSIX 消息队列的名称不是数字。 @MarkR:这是一个很好的观点,我完全错过了 - 感谢您的更正。 【参考方案1】:

是的,它们将始终通过内核(通常用于进程间通信)。如果您只想进行线程间通信,则可以通过。一个简单的工作队列(使用普通的旧互斥锁)。

如果您想要具有更多功能的东西,几乎可以肯定的是,最好看看 AMQP 之类的东西。

传统上 Unix/Linux 使用 sockets+read/write 代替,但这取决于你想要什么(以及你想如何使用它)。

【讨论】:

管道可能是另一种选择。我不知道 mqueue 是否已实现,但 tee/splice 讨论表明管道的工作效率与 Linux 下一样高。显然,管道主要通过重新映射页面来工作,从不做非绝对必要的副本。 Torvalds 在某个时候提到,他们甚至想重写 sendfile 调用以在管道机制上运行,因为据称它更快。 我打算使用 Unix 套接字,但它是基于字节的,并且真的想要面向消息/数据包的东西,因为这就是它们的用途。我在想一个简单的互斥锁 C++ std::queue 可能对我有用。 @RishiD:您可以创建 unix 域数据报套接字。只需传递用于创建 Internet 域数据报(即 UDP)套接字但使用 AF_UNIX 类型的相同标志。但请注意,数据报仍将通过内核。出于您的目的,正如 James 所建议的,使用 futex 的用户空间结构可能是最好的选择。【参考方案2】:

我不得不反对 MQ 的“高度”低效。

确实,在将数据复制到内核或从内核复制数据时会产生一些开销,对于真正高性能的应用程序,这可能是一个真正的考虑因素,也是使用共享内存或堆内存的理由。

但缺少编写良好的共享内存代码 MQ 是最快的 IPC,并带有大量内置设施。消除了同步问题,并且(至少在 linux 下)消息队列描述符 (mqd_t) 可以用作 select() 语句中的文件描述符。除了等待互斥体或不断轮询互斥体之外,这允许相当大的灵活性来做一些事情。此外,MQ 是内核持久性的,如果队列数据在应用程序崩溃后幸存下来很重要,这是一个不错的小功能。

【讨论】:

关于 mqd_t 的优点可以在 select() 中使用,这对我的应用程序很有用。感谢您的提示。

以上是关于POSIX 消息队列通过内核空间?的主要内容,如果未能解决你的问题,请参考以下文章

POSIX消息队列

POSIX消息队列

尝试使用 POSIX 消息队列创建消息队列时权限被拒绝

使用 POSIX 消息队列运行 JNA 示例

Posix消息队列

Posix消息队列