DESCRIPTION
消息隊列本身是異步的,它允許接收者在消息發送很長時間后再取回消息,這和大多數通信協議是不同的。
但消息隊列的異步特點,也造成了一個缺點,就是接收者必須輪詢消息隊列,才能收到最近的消息。
和信號相比,消息隊列能夠傳遞更多的信息。與管道相比,消息隊列提供了有格式的數據,但仍然有大小限制。
POSIX消息隊列允許進程間以消息的形式交換數據.POSIX消息隊API與System V消息隊列的API不同, 但是功能是相似的.
使用 mq_open(3) 創建和打開消息隊列; 這個函數的返回值是一個消息隊列描述符 (mqd_t), 這個描述符會在之后操作對應的消息隊列時候用到.
每一個消息隊列都有一個名字,名字的形式是 "/somename",是一個以NULL結尾的字符串,字符串的最大長度為NAME_MAX (i.e., 255);
消息隊列名字的第一個字符必須是"/",並且之后的字符中不允許出現"/"。2個進程可以通過相同的name操作同一個的消息隊列。
使用mq_send(3)可以向消息隊列中發送消息,使用mq_receive(3)可以從消息隊列中讀取消息
當一個進程使用完一個消息隊列后,調用mq_close(3)來關閉這個隊列,
如果以后再也不使用這個隊列了,可以調用mq_unlink(3)來刪除這個隊列。
消息隊列的屬性可以通過mq_getattr(3)來獲得,某些情況下這個API也可以修改消息隊列的屬性.
進程可以調用API mq_notify(3)注冊一個異步的通知,通知的觸發時機是空消息隊列中有消息到達時.
一個消息隊列描述符是對一個打開的消息隊列的引用(cf. open(2)).
The Priority of Messages
消息隊列中的消息是有優先級的, 總是將高優先級的消息先發送給接收進程。
消息的優先級從 0 (low) 到 sysconf(_SC_MQ_PRIO_MAX) - 1 (high).
在Linux中sysconf(_SC_MQ_PRIO_MAX) 的值為 32768,
但是在POSIX.1-2001中, 僅要求消息的優先級從 0 到 31。
Inherit
調用 fork(2) 后, 子進程會繼承父進程消息隊列描述符的副本,並且這些描述符與父進程中相對應的描述符指向同一個消息隊列,
2個進程中相應的描述符會共享標志mq_flags(即阻塞/非阻塞) .
Kernel configuration
是否支持 POSIX消息隊列可以通過內核配置選項 CONFIG_POSIX_MQUEUE 進行設置.
選項默認是支持POSIX消息隊列的.
Persistence
消息隊列是隨內核持續的: 如果不調用mq_unlink(3)進行刪除, 消息隊列會一直持續到系統關閉.
/proc interfaces
下面的interfaces可以用來限制POSIX message queues在內核中消耗內存的大小:
/proc/sys/fs/mqueue/msg_max
這個文件可以用來查看和修改一個消息隊列中消息的最大數.
這個值的作用,實際上與傳遞給mq_open(3)的參數 attr->mq_maxmsg 是相同的 .
msg_max 的默認值和最小值都是 10; 最大值是 HARD_MAX: (131072 / sizeof(void *)) (32768 on Linux/86).
這個限制會被有特權(CAP_SYS_RESOURCE)的進程忽略,但是上限 HARD_MAX 仍有效.
/proc/sys/fs/mqueue/msgsize_max
這個文件可以用來查看和修改消息隊列中一個消息的最大size(bytes)數.
This value acts as a ceiling on the attr->mq_msgsize argument given to mq_open(3).
msgsize_max 的默認值和最小值都是 8192 bytes; 最大值是INT_MAX (2147483647 on Linux/86).
這個限制會被有特權(CAP_SYS_RESOURCE)的進程忽略 .
/proc/sys/fs/mqueue/queues_max
這個文件可以用來查看和修改整個系統中最多可以創建的消息隊列數.
當系統中消息隊列的數目到達這個限制之后,只有 有特權的進程 (CAP_SYS_RESOURCE) 可以創建新的消息隊列.
默認值是256; 它的值可以被設置成0 到 INT_MAX 之間的任意一個值.
Resource limit
The RLIMIT_MSGQUEUE resource limit, which places a limit on the amount of space
that can be consumed by all of the message queues belonging to a process’s real user ID, is described in getrlimit(2).
Mounting the message queue file system
在 Linux中, 消息隊列是在虛擬文件系統中創建的。 (其他實現也提供這個功能,但是實現細節可能是不同的)。
消息隊列的系統可以被superuser使用下記命令掛載,如果不進行掛載會遇到遇到 mq_open: Permission denied的問題。
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue
掛載的目錄會被系統自動設置粘滯位(sticky bit)有效.
消息隊列文件系統被掛載后,消息隊列就可見了,並且可以對其使用通常的文件操作命令(e.g., ls(1) and rm(1)).
文件夾下的每個文件都只包含一行文本,內容是消息隊列的信息:
$ cat /dev/mqueue/mymq
QSIZE:129 NOTIFY:2 SIGNO:0 NOTIFY_PID:8260
這些字段的解釋如下:
QSIZE
消息隊列中所有消息的總字節數.
NOTIFY_PID
如果這個值不是0,那么PID等於這個值的進程使用了mq_notify(3) 注冊了異步消息通知,
剩下的字段描述了通知怎么發生.
NOTIFY
通知方法: 0 is SIGEV_SIGNAL; 1 is SIGEV_NONE; and 2 is SIGEV_THREAD.
SIGNO
Signal number to be used for SIGEV_SIGNAL.
Polling message queue descriptors
On Linux, a message queue descriptor is actually a file descriptor, and
can be monitored using select(2), poll(2), or epoll(7). 這是不可移植的.
POSIX Message Queue API List
- mq_close - close a message queue (REALTIME)
- mq_getattr - get message queue attributes (REALTIME)
- mq_notify - notify process that a message is available (REALTIME)
- mq_open - open a message queue (REALTIME)
- mq_receive - receive a message from a message queue (REALTIME)
- mq_timedreceive - receive a message from a message queue (REALTIME)
- mq_send - send a message to a message queue (REALTIME)
- mq_timedsend - send a message to a message queue (REALTIME)
- mq_setattr - set message queue attributes (REALTIME)
- mq_timedreceive - receive a message from a message queue (ADVANCED REALTIME)
- mq_timedsend - send a message to a message queue (ADVANCED REALTIME)
- mq_unlink - remove a message queue (REALTIME)