Posix消息队列

消息队列

简介

前面我们已经介绍了两种消息传递方式,管道以及FIFO.下面我们来介绍第三种:消息队列.

  • 消息队列不同于管道和FIFO,其具有内核级持续性.也就是说,如果我们没有主动删除这个队列,它会生存到操作系统关闭.
  • 我们可以将消息队列看做一个priority_queue,我们向其中send一个数据并设置它的优先级,当进程执行receive时会首先得到优先级高的数据.
  • 不同于管道以及FIFO,消息队列是有"边界"的,也就是说我们传递的是"包",而不是数据流.
  • 消息队列并不对打开操作做出要求,也就是说我们可以直接打开消息队列并向其中写入数据而不用考虑此时是否有进程在读.写完之后我们也可以直接关闭消息队列,其他的进程可以在任意时间内对数据进行读取.

相关函数

  • mq_open

    • 函数原型:
      mqd_t mq_open(const char *name,int aflag, ...//mode_t mode, struct mq_attr *attr);
    
    • aflag: O_RDONLY, O_WRONLY, O_RDWR.见字面含义.
      O_CREAT指创建一个新的消息队列,O_EXCL指定在目标文件不存在时才创建,如果存在则返回一个EEXIST错误.
    • 当我们要创建一个文件时,则需要填入mode属性(同FIFO的mode)以及mq_attr结构体以指定一些属性.如果结构体指针为NULL则使用默认属性.
    • mq_open的返回值被称为消息队列描述符,其真实值并不一定是int(看具体实现)
  • mq_close

    • 参数值为mq_open的返回值.
    • 调用close并不会删除该消息队列,只是调用进程不再使用该描述符.
    • 当一个进程退出时,它的所有的打开着的消息队列都会关闭.
  • mq_unlink

    • 参数值为mq_open的返回值
    • 当我们调用mq_unlink的时候,该消息队列并没有真实的被删除,而是删除了名字使我们无法再重新open
    • 消息队列在内核中同样维持了一个计数器,每次我们调用close的时候都会将计数器-1.当没有引用的时候计数器值为1,直到我们调用unlink计数器才会变为0.计数器变为0时该消息队列被真正删除
  • mq_getattr

    • 第一个参数为me_open返回值,第二个参数为mq_attr结构体的指针
    • mq_attr结构体具有以下属性:
        struct me_attr{
            long mq_flags;
            long mq_maxmsg;
            long mg_msgsize;
            long mq_curmsgs;
        }
    
    • 调用mq_getattr返回该消息队列的属性.
  • mq_setattr

    • 函数原型:
        int mq_setattr(mqd_t mqdes, const struct mq_attr *attr,struct mq_attr *oattr);
    
    • 我们可以通过参数attr设置标志位mq_flags,结构体其他的三个参数会被忽略(maxmsg以及msgsize只能在创建时设定).
    • 参数oattr如果不是NULL则会返回更改之前的状态.
  • mq_send

    • 函数原型:
        int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);
            //成功则返回0,失败则为-1
    
    • mqdes参数为me_open的返回值
    • ptr是我们要发送的数据指针.如果我们需要发送一个struct的话,可能需要类型转换以下(char*)&targetStruct.
    • len参数是我们发送的数据大小
    • prio参数是该条数据的优先级(小于MQ_PRIO_MAX的无符号整数)
  • mq_receive

    • 函数原型:
      ssize_t mq_receive(mqd_t mqdes, const char *ptr, size_t len, unsigned int *prio);
                //成功则返回消息中字节数,失败则为-1
    
    • mqdes参数为me_open的返回值
    • ptr参数:传入一个缓冲区来接收数据
    • len参数:len参数不能小于mq_attr中的mq_msgsize成员,否则立即返回EMSGSIZE错误
    • prio参数:通过传入一个int型指针存储该条信息的优先级

notify机制

- 介绍: 当我们receive的时候如果队列中没有数据,在阻塞模式下,进程会阻塞直到有数据写入队列中.  
  如果设置了NONBLOCK,虽然不再阻塞但是需要持续调用函数以确定消息到达(轮询).

- mq_notify函数:
    - Posix消息队列提供了异步事件通知.以告知何时有一个消息放置到了某个空消息队列.
    - 函数原型:
    ```
        int mq_notify(mqd_t mqdes, const struct sigevent *notification)
                    //成功则返回0,失败则返回-1
    ```
    - 我们通过notify来为该事件注册一个信号.如果该事件发生则产生一个信号给注册进程.从而我们可以通过回调来实现对消息队列的读取.
posted @ 2017-03-11 10:49  XLLL  阅读(211)  评论(0编辑  收藏  举报