52 POSIX 消息队列

和 System V 不同点:

消息按照优先级排序

消息按照优先级排序(数值越小越靠前)。每次接收都只能拿到开头的消息,不像 SysV 消息队列那样不按照优先级排序、且可以选择性获取中间的消息。

注册消息通知

POSIX 消息队列还有一个功能就是能够注册消息通知,以得到有消息来临的消息:

  1. 任何时候只能有一个进程可以注册特定队列的消息通知(第二个进程注册时会失败得到 EBUSY 错误)。进程也可以主动解除通知。
  2. 消息通知是一次性的,通知完成之后就会自动解除。
  3. 只有消息队列从空变成非空时,才可能有通知。在非空的状态下来消息是不会产生通知的,只能先清空再来消息才可以产生通知。
  4. 消息队列从空变成非空时,如果有其他因为调用 mq_receive() 而阻塞的进程,那么消息由其中的一个进程获取,而不会产生通知!!

API:

SYNOPSIS
       #include <mqueue.h>
       #include <signal.h>           /* Definition of SIGEV_* constants */

       int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

sigevent 类型可以通过 system_data_types(7) 和 sigevent(7) 查到,它允许我们选择用一个自选信号通知,或者选择创建一个新线程处理通知(这个新线程要运行的函数由我们来指定)。

和 POSIX 消息队列相关的 Linux 特性

mqueue 虚拟文件系统

可以用 mount -t mqueue none /dev/mqueue 挂载 mqueue 虚拟文件系统。在我的系统上,这个文件系统已经存在于 /dev/mqueue 了,不需要手动挂载,通过 cat /proc/mounts 就能看到。

Tip

除了能够看到 /dev/mqueue 是 mqueue 文件系统之外,还能看到 /dev/shm 是 tmpfs 文件系统。

多路复用

消息队列描述符实际上是文件描述符,可以用 I/O 多路复用的 API(select/poll/epoll)来监听。

资源限制

  • MQ_PRIO_MAX:消息的最大优先级。
  • MQ_OPEN_MAX:进程最多能打开的消息队列数量。Linux 没有这个限制,但是因为消息队列描述符被实现为文件描述符,所以受到进程可以打开的文件描述符数量限制。
  • msg_max:新创建消息队列可以选择的优先级上限(默认值 10)。
  • msgsize_max:新创建消息队列可以选择的消息大小上限(默认值 8192,最小值 128,最大值 1048576,但可能随着内核版本会变化)。
  • queues_max:系统上能创建消息队列的最大数量,默认为 256。