进程通信学习笔记(Posix消息队列)

在某个进程往一个队列写入消息之前,并不需要另外有个进程在该队列上等待消息的到达,这跟管道和FIFO是相反的,对于后两者来说,除非读出者已存在,否则先有写入者是没有意义的

1、mq_open、mq_close和mq_unlink函数

mq_open函数创建一个新的消息队列或者打开一个已存在的消息队列

#include
mqd_t mq_open(const char *name, int oflags, .../*mode_t mode, struct mq_attr *attr*/);

成功返回消息队列描述字,失败返回-1

oflags参数是O_RDONLY、O_WRONLY、O_RDWR之一,可能按位或上O_CREAT、O_EXCL或O_NONBLOCK

当操作是创建一个队列时,mode和attr参数是需要的。attr参数用于给新队列指定某些属性,如果它为空指针,就使用默认属性

消息队列描述字与文件或套接口描述字是不一样的

已打开的消息队列用mq_close关闭

#include
int mq_close(mqd_t mqdes);

成功返回0,失败返回-1

要从系统中删除用作mq_open第一个参数的某个name,必须用mq_unlink

#include
int mq_unlink(const char *name);

成功返回0,失败返回-1

编译时注意:

(1)、添加目录,挂载消息队列虚拟文件系统

mkdir /dev/mqueue

mount -t mqueue none /dev/mqueue

(2)、指定name时用这种形式/pathname

(3)、添加-lrt

2、mq_getattr和mq_setattr函数

每个消息队列有四个属性,mq_getattr返回所有的这些属性,mq_setattr则设置其中某个 属性

#include
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

mq_attr结构定义如下:

struct mq_attr

{

    long mq_flags;  //message queue flag:0, O_NONBLOCK

    long mq_maxmsg;   //队列中允许的最大的消息数目

    long mq_msgsize;//单个消息的最大大小

    long mq_curmsgs;//当前消息队列中的消息个数

};

指向某个mq_attr结构的指针可作为mq_open的第四个参数,从而允许在该函数的实际操作中创建一个消息队列,给它指定mq_maxmsg和mq_msgsize属性.mq_open忽略该结构的另个两个成员

mq_getattr把所指定队列的当前属性填入attr指向的结构

mq_setattr给指定的队列设置属性,只能设置mq_flags,每个队列的最大消息数和每个消息的最大字节数只能在创建时设置,当前消息数则只能获取不能设置

3、mq_send和mq_receive函数

每个消息有一个优先级,小于MQ_PRIO_MAX的无符号整数

mq_receive总是返回指定队列中的优先级最高的最早消息,而且该优先级能随该消息的内容及其长度返回

#include
int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);   成功返回0,失败返回-1

int mq_receive(mqd_t mqdes, char *ptr, size_t lne, unsigned int *prio);  成功返回消息中的字节数,失败返回-1

4、消息队列的限制

有两个限制:

(1) MQ_OPEN_MAX:一个进程同时打开的消息队列的最大数目

(2)MQ_PRIO_MAX:任意消息的最大优先级值 加1

5、mq_notify函数

适用情况:往空队列中放置了一个消息

两种方式 :

(1)产生一个信号
(2)创建一个线程执行一个指定的函数

函数定义

#include
int mq_notify(mqd_t mqdes, const struct sigevent *notification);

成功返回0,失败返回 -1

信号常值 都 定义在头文件中

union sigval

{

   int sival_int;

   void *sival_ptr;

};

struct sigevent

{

    int sigev_notify;//通知类型,有SIGEV_(NONE, SIGNAL, THREAD)

    int sigev_signo;//SIGEV_SIGNAL时的信号值

    uniong sigval sigev_value;//传递给信号处理函数或者线程的值

    void (*sigev_notify_function)(union sigval);

    pthread_attr_t *sigev_notify_attributes;

};

函数的若干规则:

(1)notification非空,表示有一个消息到达该队列并且先前为空时得到通知

(2)notification为空,表示注册被撤销

(3)任意时刻只有一个进程可以注册为接收某个队列的通知

(4)当有一个消息到达先前为空的队列时,且有一个进程注册为接收该队列的通知时,只有没有任何线程阻塞在该队列的mq_receive调用的前提下,通知才会发出。即mq_receive调用 中的阻塞优先于任何通知的注册

(5)当通知发送给注册进程时,其注册被撤销,须再次调用 mq_notify注册





你可能感兴趣的:(进程通信)