1 概述
- 消息队列可认为是一个消息链表。
- 在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达【消息队列具有随内核的持续性】。这跟管道和FIFO是相反的。后两者,除非读出者已存在,否则先有写入者是无意义的。当一个管道或FIFO的最后一次关闭发生时,仍在该管道或FIFO上的数据将被丢弃。
Posix消息队列与System V消息队列的主要差别
- 对Posix消息队列的读总是返回最高优先级的最早信息,对System V消息队列的读则可以返回任意指定优先级的消息。
- 当往一个空队列放置一个消息时,Posix消息队列允许产生一个信号或启动一个线程,System V消息队列则不提供类似机制。
消息队列的可能布局
其中mq_maxmsg是队列中允许的最大消息数,mq_msgsize每个消息的最大大小。
2 mq_open、mq_close、mq_unlink函数
- mq_open函数创建一个新的消息队列或打开一个已存在的消息队列。
#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag, ...,);
// 若成功则返回消息队列描述符,否则返回-1
-
mq_close函数关闭已打开的消息队列。关闭时,调用进程不再使用该描述符,但其消息队列并不从系统中删除。一个进程终止时,它的所有打开着的消息队列都关闭。
#include <mqueue.h> int mq_close(mqd_t mqdes); // 若成功则返回0,否则返回-1
-
调用mq_unlink从系统中删除用作my_open第一个参数的某个name。
#include <mqueue.h> int mq_unlink(const char *name); // 成功则返回0,否则返回-1
3 mq_getattr 和 mq_setattr函数
- 指向某个mq_attr结构的指针可作为mq_open的第四个参数传递,从而运行我们在该函数的实际操作是创建一个新队列。
// 均返回:成功则为0,失败则为-1
#include <mqueue.h>
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *attr, struct mq_attr *oattr);
struct mq_attr {
long mq_flags; // message queue flag: 0, O_NONBLOCK
long mq_maxmsg; // max number of messages allowed on queue
long mq_msgsize; // max size of a message
long mq_curmsgs; // number of messages currently on queue
}
- mq_getattr把所指定队列的当前属性填入由attr指向的结构;
- mq_setattr给所指定队列设置属性。
4 mqgetattr程序
- Note:Mq_getattr(mqd, &attr);
#include "unpipc.h" int main(int argc, char const *argv[]) { mqd_t mqd; struct mq_attr attr; if (argc != 2) { err_quit("usage: mqgetattr <name>"); } mqd = Mq_open(argv[1], O_RDONLY); Mq_getattr(mqd, &attr); printf("max #msgs = %ld, max #bytes /msg = %ld," "#currently on queue = %ld\n", attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); Mq_close(mqd); exit(0); }
5 mq_send和mq_receive函数
-
这两个函数分别用于往一个队列中放置一个消息和从一个队列中取走一个消息。每个消息有一个优先级,它是一个小于MQ_PRIO_MAX的无符号整数。
-
mq_receive总是返回所指定队列中最高优先级的最早消息,而且该优先级能随该消息的内容及其长度一同返回。
#include <mqueue.h> // 成功返回0,否则返回-1 int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio); // 成功返回消息中字节数,否则返回-1 ssize_t mq_receive(mqd_t mqdes, char *ptr, ssize_t len, unsigned int *priop); ``` - 5.1 例子:mqsend程序 ```bash mqcreate /test1 mqsend /test1 100 6
5.1 例子:mqsend程序
#include "unpipc.h"
int main(int argc, char const *argv[])
{
mqd_t mqd;
void *ptr;
size_t len;
uint_t prio;
if (argc != 4)
{
err_quit("usage: mqsend <name> <#bytes> <priority>")
}
len = atoi(argv[2]);
prio = atoi(argv[3]);
mqd = Mq_open(argv[1], O_WRONLY);
ptr = Calloc(len, sizeof(char));
Mq_send(mqd, ptr, len, prio);
exit(0);
}
5.2 例子:mqreceive程序
#include "unpipc.h"
int main(int argc, char const *argv[])
{
int c, flags;
mqd_t mqd;
ssize_t n;
uint_t prio;
void *buff;
struct mq_attr attr;
flags = O_RDONLY;
// 允许-n选项以指定非阻塞属性。
// 这样若所指定队列中午消息,mqreceive会返回一个错误
while ( (c = Getopt(argc, argv, "n")) != -1) {
switch (c) {
case 'n':
flags |= O_NONBLOCK;
break;
}
}
if (optind != argc - 1)
err_quit("usage: mqreceive [-n] <name>");
mqd = Mq_open(argv[optind], flags);
Mq_getattr(mqd, &attr);
buff = Malloc(attr.mq_msgsize);
n = Mq_receive(mqd, buff, attr.mq_msgsize, &prio);
printf("read %ld bytes, priority = %u\n", (long) n, prio);
exit(0);
}
6 mq_notify函数
Posix消息队列允许异步事件通知,以告知何时有一个消息放置到了某个空消息队列中。这种通知通过调用mq_notify建立,有两种方式可选择:
- 产生一个信号;
- 创建一个线程来执行一个指定的函数;
#include <mqueue.h>
int mq_notify(mqd_t mqdes, const struct sigevent *notification); // 返回:成功返回0. 否则返回-1