5.1 概述
消息队列可以认为是一个链表。有写权限的线程可往消息队列中放置消息,有读权限的线程可以从消息队列中取走消息。
消息队列和管道/FIFO的区别:
(1)消息队列往一个队列中写消息前,并不需要有一个进程/线程在等待消息的到达,管道/FIFO需要。
(2)Posix消息队列是随内核的持续性,管道/FIFO是随进程的。
Posix消息队列和System V消息队列的区别:
(1)Posix消息队列的读总是返回最高优先级(类型)的最早消息;System V消息队列的读可以返回指定优先级(类型)的消息;
(2)Posix消息队列可以产生一个信号,System V消息队列不可以。
5.2 函数
5.2.1 mq_open函数
头文件 | #include <mqueue.h> |
函数原型 | mqd_t mq_open(const char *name, int oflag); |
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr); | |
返回值 | 成功返回消息队列的描述符,失败返回-1 |
name:只能以/开头,且之后不能有/ | |
参数 | oflag:O_RDONLY、O_WRONLY、O_RDWR、O_CREAT、O_EXCL、O_NOBLOCK |
mode:0666 | |
说明 | 1.有2个函数的原因和open函数一样,参数中有...可变参数 |
2.第4个参数,有的版本传变量的地址,有的版本传变量 |
5.2.2 mq_close函数
头文件 | #include <mqueue.h> |
函数原型 | int mq_close(mqd_t mqdes); |
返回值 | 成功返回0,失败返回-1 |
说明 | 只是关闭消息队列描述符,但消息队列还在系统中 |
5.2.3 mq_unlink 函数
头文件 | #include <mqueue.h> |
函数原型 | int mq_unlink(const char *name); |
返回值 | 成功返回0,失败返回-1 |
说明 | 删除消息队列 |
注意:
1.编译时需要加上 -lrt
2.程序编译完成后,如果直接运行程序则提示mq_open失败,提示mq_open permission denied。解决办法是:
mkdir /dev/mqueue
mount -t mqueue none /dev/mqueue
5.2.4 mqcreat 程序
#include <stdio.h> #include <unistd.h> #include <mqueue.h> // mqcreat -e /mqueue int main(int argc, char **argv) { ; int flags = O_RDWR | O_CREAT; mqd_t mqd = ; ) { switch (c) { case 'e': flags |= O_EXCL; break; default: break; } } ) { printf("usage: mqcreate [-e] <name>\n"); ; } // 打开或创建一个消息队列 mqd = mq_open(argv[optind], flags, , ); ) { perror("mq_open error"); ; } // 关闭消息队列 mq_close(mqd); // 删除消息队列 //mq_unlink(argv[optind]); ; }
5.3 消息队列的属性
struct mq_attr {
long mq_flags; /* Flags: 0 or O_NONBLOCK */
long mq_maxmsg; /* Max. # of messages on queue */
long mq_msgsize; /* Max. message size (bytes) */
long mq_curmsgs; /* # of messages currently in queue */
};
每个消息队列有4个属性:是否阻塞、允许最大的消息数量、允许最大的字节、当前消息数量。
1.如果创建一个新队列,指定了mq_maxmsg、mq_msgsize则忽略其他两个成员。
2.如果设置成非阻塞的,则另外三个参数被忽略。
头文件 | #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); | |
返回值 | 成功返回0,失败返回-1 |
5.3.1 带属性的mq_creat程序
#include <stdio.h> #include <unistd.h> #include <string.h> #include <mqueue.h> // mqcreat -e -m 1024 -z 8192 /mqueue int main(int argc, char **argv) { ; int flags = O_RDWR | O_CREAT; mqd_t mqd = ; struct mq_attr attr; memset(&attr, , sizeof(attr)); ) { switch (c) { case 'e': flags |= O_EXCL; break; case 'm': attr.mq_maxmsg = atol(optarg); break; case 'z': attr.mq_msgsize = atol(optarg); break; default: break; } } ) { printf("usage: mqcreate [-e] <name>\n"); ; } // 打开或创建一个消息队列 mqd = mq_open(argv[optind], flags, , attr); ) { perror("mq_open error"); ; } // 关闭消息队列 mq_close(mqd); // 删除消息队列 mq_unlink(argv[optind]); ; }
5.4 mq_send 和 mq_receive 函数
mq_send是往消息队列中放消息;mq_receive从消息队列中取消息。每个消息都有一个优先级(类型),它是一个小于MQ_PRIO_MAX的无符号整数,Posxi的上限是32。
mq_receive总是返回队列中在最高优先级的最早消息。而System V的msgrcv函数可以返回指定优先级的最早消息。
头文件 | #include <mqueue.h> |
函数原型 | int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio); |
返回值 | 成功返回0,失败返回-1 |
函数原型 | ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio); |
返回值 | 成功返回字节数,失败返回-1 |
说明 | 1.mq_receive的len参数不能小于消息的最大值(mq_attr结构中mq_msgsize成员),如果小于就立即返回EMSGSIZE错误 |
2.mq_send的prio参数是待发消息的优先级(类型),其值必须小于32位无符号整数 | |
3.mq_receive的prio参数如果非空,所返回消息的优先级(类型)就放在这个地址中 | |
4.如果不需要指定优先级,则mq_send的prio参数为0,mq_receive的prio参数为NULL |
5.4.1 mqsend程序
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <mqueue.h> // mqsend /mqueue 100 1 int main(int argc, char **argv) { ; int flags = O_RDWR | O_CREAT; mqd_t mqd = ; struct mq_attr attr; memset(&attr, , sizeof(attr)); ) { printf("usage: mqsend <name> <bytes> <priority>\n"); ; } // 打开或创建一个消息队列 mqd = mq_open(argv[], flags, , NULL); ) { perror("mq_open error"); ; } unsigned ]); unsigned ]); , len); int ret = mq_send(mqd, ptr, len, prio); ) { perror("mq_send error"); ; } // 关闭消息队列 mq_close(mqd); ; }
5.4.2 mqreceive程序
命令行选项-n指定非阻塞模式,这样消息队列中没有消息,mq_receive就返回一个错误。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <mqueue.h> // mqreceive [-n] /mqueue int main(int argc, char **argv) { ; int flag = O_RDWR | O_CREAT; mqd_t mqd = ; struct mq_attr attr; unsigned ; ) { switch (c) { case 'n': flag |= O_NONBLOCK; break; default: break; } } ) { printf("usage: mareceive [-n] <name>\n"); ; } // 打开消息队列 mqd = mq_open(argv[optind], flag, , ); ) { perror("mq_open error"); ; } // 获取消息队列中消息的最大字节数 mq_getattr(mqd, &attr); ); int n = mq_receive(mqd, buff, attr.mq_msgsize, &prio); printf("read %d bytes, prio:%d\n", n, prio); ; }
5.5 消息队列限制
mq_maxmsg 队列中的最大消息数,没有限制
mq_msgsize 消息的最大字节数,没有限制
MQ_OPEN_MAX 一个进程能同时打开消息队列的最大数目,有限制,查询方法是:sysconf(_SC_MQ_OPEN_MAX);
MQ_PRIO_MAX 消息的优先级要小于这个值,有限制,查询方法是:sysconf(_SC_MQ_PRIO_MAX);