消息队列可以认为是一个消息链表,其含有优先级。在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。
ls /dev/mqueue
命名规则
只能以 / 开头。
接口
头文件:mqueue.h
库:librt.so(-lrt //链接)
结构体
struct mq_attr //消息队列属性
成员 | 含义 | 说明 |
---|---|---|
mq_flags | 标志 | 在mq_open时被初始化,在mq_setattr设置,其值为0或者O_NONBLOCK(O_RDONLY,O_WRONLY,O_RDWR |
ma_msgsize | 队列每个消息长度的最大值 | 只能在mq_open时被初始化 |
mq_curmsgs | 当前队列消息的个数 | 在mq_getattr获取 |
操作 | 函数 |
---|---|
创建消息队列 | mdq_t mq_open(const char *name,int oflag,mode_t mode,struct mq_attr *attr) |
删除消息队列 | int mq_unlink (const char *name) |
打开消息队列 | int mq_open(const char *name,int oflag) |
关闭消息队列 | int mq_close(mqd_t mqdes) |
发送消息 | int mq_send(mqd_t mqdes,const char* msg_ptr,size_t msg_len,unsigned msg_prio),最后一个参数是优先级,数字越大优先级越高(注意优先级有上限) |
接受信息 | int mq_receive(mqd_t mqdes,const char* msg_ptr,size_t msg_len,unsigned *msg_prio),总是返回指定队列最高优先级的最早消息,而且该优先级能随该消息内容及其长度一起返回,其返回值是接受信息的字节数。 |
设置消息队列属性 | int mq_setattr(mqd_t mqdes,struct mq_attr *newattr,struct mq_attr *oldattr) |
获取消息队列属性 | int mq_getattr(mqd_t mqdes,struct mq_attr *attr) |
待发送信息的大小和优先级必须作为命令行参数指定。
mq_receive的len参数的值不能小于加到指定队列的消息的最大消息长度。也就是在打开消息队列后,要进行mq_getattr确定最大消息大小,然后分配那样大小的缓冲区。
mq_setattr只能设置阻塞或者非阻塞。
mq_close功能和关闭一个打开文件的close类似:调用进程可以不再使用该描述符,但是其消息队列并不从系统中删除。
要从系统中删除某个消息队列,必须使用mq_unlink
每个消息队列都有一个保存当前打开着的描述符的引用计数器,使用mq_unlink从系统中删除该名字意味着引用计数减一,若变为0才是真正的拆除该队列。
posix消息队列具备随内核的持续性。也就是说,即使当前没有进程打开某个消息队列,该队列及其上的各个消息也一直存在,直到引用计数为0才删除。
mqd_t mq_open(const char *name,int oflag,mode_t mode,struct mq_attr *attr)
//attr选项为NULL,是默认属性
//若是不为NULL,在创建之前就要设置好struct mq_attr attr的相关变量
参数 | 含义 |
---|---|
name | posix IPC 名字,格式为/somename |
oflag | 标志 |
mode | 权限 |
attr | 队列属性,阻塞attr.mq_flag=0;非阻塞attr.mq_flag=NONBLOCK |
标志 | 作用 |
---|---|
O_CREAT | 没有该对象则创建 |
O_EXCL | 如果O_CREAT指定,但name不存在,就返回错误 |
O_NONBLOCK | 以非阻塞的方式打开消息队列 |
O_RDONLY | 只读 |
O_WRONLY | 只写 |
O_RDWR | 读写 |
自行在man手册查看,此处可以0000形式设置
例如0777:即所有人有所有权限
返回值 | 含义 |
---|---|
-1 | 出错 |
其他 | 消息队列描述符 |
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open()
#define FILE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH) //0644
int main(){
struct mq_attr attr;
attr.mq_maxmsg = 100;
attr.mq_msgsize = 100;
mqd_t mqd = mq_open("/tmp.test",O_CREAT,FILE_MODE,&attr);
if(-1 == mqd){
perror("mq_open error");
return 1;
}
}
编译时需加上 -lrt
int mq_unlink(const char *name)
参数 | 含义 |
---|---|
name | posixIPC名字 |
返回值 | 含义 |
---|---|
-1 | 出错 |
0 | 成功 |
mqd_t mq_open (const char*name,int oflag)
返回值 | 含义 |
---|---|
-1 | 出错 |
其他 | 描述符 |
int mq_close(mqd_t mqdes)
参数:mqdes含义是消息队列描述符
返回值 | 含义 |
---|---|
-1 | 出错 |
0 | 成功 |
int mq_send(mqd_t mqdes,const char* msg_ptr,size_t msg_len,unsigned msg_prio)
参数 | 含义 |
---|---|
msg_ptr | 消息的指针 |
msg_len | 消息长度,不能大于属性值mq_msgsize的值 |
msg_prio | 优先级,小于MQ_PRIO_MAX,数值越大,优先级越高 |
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_send() mq_close()
int main(int argc,char* argv[]){
mqd_t mqd = mq_open("/tmp.test",O_WRONLY); // 可以设置O_NONBLOCK
if(-1 == mqd){
perror("mq_open error");
return 1;
}
const char* msg = "HelloWorld";
if(-1 == mq_send(mqd,msg,sizeof(msg),1)){
perror("mq_send error");
mq_close(mqd);
return 1;
}
mq_close(mqd);
return 0;
}
ssize_t mq_receive(mqd_t mqdes,char *msg_ptr,size_t msg_len,unsigned *msg_prio)
参数 | 含义 |
---|---|
msg_ptr | 消息指针 |
msg_len | 消息长度,不能大于属性值mq_msgsize的值 |
msg_prio | 优先级 |
返回值 | 含义 |
---|---|
-1 | 出错 |
正数 | 收到消息的长度 |
POSIX消息队列在调用mq_receive()时总是返回队列中最高优先级的最早消息。
如果队列空,mq_receive()函数将阻塞,直到消息队列中有新的消息。
如果O_NONBLOCK被指定,mq_receive()那么将不会阻塞,而是返回EAGAIN错误。
int mq_setattr(mqd_t mqdes,strcut mq_attr* newattr,struct mq_attr* oldattr)
参数 | 含义 |
---|---|
mqdes | 消息队列描述符 |
newattr | 新属性,只能设置mq_flag:O:NONBLOCK |
oldattr | 旧属性 |
返回值 | 含义 |
---|---|
-1 | 出错 |
0 | 成功 |
#include <stdio.h> // perror()
#include <string.h> // bzero()
#include <mqueue.h> // mq_open() mq_setattr() mq_close()
int main(){
mqd_t mqd = mq_open("/tmp.test",O_RDWR);
if(-1 == mqd){
perror("mq_open error");
return 1;
}
struct mq_attr new_attr;
bzero(&new_attr,sizeof(new_attr));
new_attr.mq_flags = O_NONBLOCK;
struct mq_attr attr;
if(-1 == mq_setattr(mqd,&new_attr,&attr)){
perror("mq_setattr error");
mq_close(mqd);
return 1;
}
printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
mq_close(mqd);
}
int mq_getattr(mqd_t mqdes,struct mq_attr * attr)
参数 | 含义 |
---|---|
mqdes | 消息队列描述符 |
attr | 属性 |
返回值 | 含义 |
---|---|
-1 | 出错 |
0 | 成功 |
#include <stdio.h> // perror()
#include <mqueue.h> // mq_open() mq_getattr() mq_close()
int main(){
mqd_t mqd = mq_open("/tmp.test",O_RDONLY);
if(-1 == mqd){
perror("mq_open error");
mq_close(mqd);
return 1;
}
struct mq_attr attr;
mq_getattr(mqd,&attr);
printf("flag:%ld,Max msg:%ld,Max msgsize:%ld,Cur msgnun:%ld\n",attr.mq_flags,attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
mq_close(mqd);
return 0;
}
mq_setattr()可以设置的属性只有mq_flags,用来设置或清除消息队列的非阻塞标志。newattr结构的其他属性被忽略。
mq_maxmsg和mq_msgsize属性只能在创建消息队列时通过mq_open()来设置。
mq_open()只会设置该两个属性,忽略另外两个属性。
mq_curmsgs属性只能被获取而不能被设置。
异步事件通知,以告知何时有一个消息放置在某个空的消息队列。这种通知有两种方式:
1.产生一个信号
2.创建一个线程来执行一个指定的函数
这种通知通过调用mq_notify建立
#include <mqueue.h>
int mq_notify(mqd_t mqdes,const struct sigevent *notification);
//该函数为指定队列建立或删除异步事件通知
#include <signal.h>
union sigval{
int sival_int;
void *sival_ptr;
};
struct sigevent{
int sigev_notify;
int sigev_signo;
union sigval sigev_value;
void (*sigev_notify_function)(union sigval);
pthread_attr_t *sigev_notify_attributes;
};
1.如果notification参数非空,那么当前进程希望在有一个消息到达所指定的先前为空的队列得到通知。“该进程被注册为接受该队列的通知”
2.如果notification为空指针,且当前进程目前被注册为接受所指定队列的通知,那么已存在的注册将被注销。
3.任意时刻只有一个进程被注册为接收某个队列的通知。
4,.当该通知被发送给他的注册进程时,其注册即被撤销。该进程必须再次调用mq_notify重新注册。
避免从信号处理程序中调用任何函数的方法之一是:让处理程序设置一个全局标志,由某个线程检查该标志以确定何时接收到一个消息。
问题:
在第一个消息被读出之前有两个消息到达。通知只是在有一个消息被放置在某个空队列上时才发出。如果在能够读出第一个消息前有两个消息到达,那么只有一个消息发出:我们读出第一个消息,并调用sigsuspend等待另一个消息,而对应他的通知永远也不会发出。另一个放置在队列等待的消息,被忽略。
上一个程序通过调用sigsuspend阻塞,以等待某个消息到达。当有一个消息被放置在空的消息队列中,该信号产生,主线程被阻止,信号处理程序执行并设置mqflag变量,主程序在执行,发现mq_flag非零,于是读出该消息。更为简易的方式是阻塞在某个函数,仅仅等待该辛哈的递交,而不是让内核执行一个只为设置一个标志的信号处理程序。
#include <signal.h>
int sigwait(const sigset_t *set,int *sig);