1.消息队列
消息队列可以认为是一个消息链表,消息队列是随内核持续的。队列中每个消息的属性有:一个无符号整数优先级(Poxis)或一个长整数类型(System V);消息的数据部分长度(可以为0);数据本身。链表头含有当前队列的两个属性:队列中运行的最大消息数、每个消息的最大大小。消息队列的可能布局如下:
Posix消息队列与System V消息队列主要区别:
1.对Posix消息队列的读总是返回最高优先级的消息,对System V消息队列的读则可以返回任一指定优先级消息。
2.往空队列放置消息时,Posix消息队列允许产生一个信号或启动一个线程,System V则不提供类似机制
Posix消息队列与管道或FIFO的主要区别:
1.在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。对管道和FIFO来说,除非读出者已存在,否则先有写入者是没有意义的。
2.管道和FIFO是字节流模型,没有消息边界;消息队列则指定了数据长度,有边界。
2.mq_open 、 mq_close、 mq_unlink
//创建新消息队列或打开已存在的消息队列
#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag, .../*mode_t mode, struct mq_attr *attr*/);
返回值:成功,消息队列描述符;失败,-1
消息队列描述符用作其余消息队列函数(mq_unlink除外)的第一个参数。
name规则:必须以一个斜杠符打头,并且不能再包含任何其他斜杠符
oflag:O_RDONLY、O_WRONLY、O_RDWR三者之一,按位或上O_CREAT、O_EXCL
mode:S_ISRUSR、S_ISWUSR、S_ISRGRP、S_ISWGRP、S_ISROTH、S_ISWOTH
attr:
struct mq_attr
{
long mq_flags;//阻塞标志, 0或O_NONBLOCK
long mq_maxmsg;//最大消息数
long mq_msgsize;//每个消息最大大小
long mq_curmsgs;//当前消息数
};
//关闭已打开的消息队列
int mq_close(mqd_t mqd);
返回值:成功,0;出错,-1
一个进程终止时,它的所有打开的消息队列都关闭,如同调用了mq_close。
//删除消息队列的name
int mq_unlink(const char *name);
返回值:成功,0;出错,-1
每个消息队列有一个保存其当前打开的描述符数的引用计数,只有当引用计数为0时,才删除该消息队列。mq_unlink和mq_close都会让引用数减一
例1:创建一个消息队列,并可使用排他性检验
程序:
#include <stdio.h>
#include <mqueue.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(int argc, char *argv[])
{
int c;
int flag = O_RDWR | O_CREAT;
while ((c = getopt(argc, argv, "e")) != -1)
{
switch(c)
{
case 'e':
flag |= O_EXCL;
break;
}
}
if (optind != argc -1)
{
printf("usage: mqcreate [- e] <name>\n");
exit(0);
}
mqd_t mqd = mq_open(argv[optind], flag, FILE_MODE, NULL);
if (mqd == -1)
{
printf("mq_open() error %d : %s\n", errno, strerror(errno));
exit(-1);
}
mq_close(mqd);
exit(0);
}
分析:
1.mq_xxx()函数不是标准库函数,所以链接时需指定库,通过在最后加上-lrt选项来指定。
2.程序运行之后可能会看不到消息队列,要看到创建的Posix消息队列,需执行以下操作:
mkdir /dev/mqueue
mount -t mqueue none /dev/mqueue
3.程序通过getopt()函数获取带选项的命令行参数,optind指向下一个要读取的参数在argv[]中的位置。若遇到没包含在getopt第三个参数的选项字母,或者遇到一个没有所需参数的选项字母(通过在第三个参数后跟一个冒号指示)则出错。
4.若命令行参数带有-e选项,则进行排他性检测。
5.若mq_open()出错,则通过strerror(errno)函数得到错误说明。
结果:
例2:使用mq_unlink删除一个消息队列
程序:
#include <stdio.h>
#include <mqueue.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("argument error\n");
exit(-1);
}
int val = mq_unlink(argv[1]);
if (val != 0)
{
printf("mq_unlink() error %d : %s\n", errno, strerror(errno));
exit(-2);
}
exit(0);
}
分析:通过strerror(errno)得到错误信息
结果