Linux系统编程--POSIX消息队列

打开一个消息队列

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

POSIX IPC对象需要使用以斜线开头后面跟着一个或多个非斜线字符的名字
例如 /mq
oflag是位掩码

标记 描述
O_CREAT 不存在时创建
O_EXCL 和O_CREAT一起排他创建
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_NONBLOCK 非阻塞

如果使用非阻塞方式打开,那么后续对此mqd_t的操作都会以非阻塞的方式进行
如果指定了O_CREATE,就需要mode 和attr参数(如果已经存在,则会忽略)
mode和open一样(0777…)
attr是mq_attr结构,指定了消息队列的特性。如果为NULL则会以默认特性创建。

fork() exec() 进程终止后的影响

fork()中子进程会接受父进程的消息队列描述符的副本,但是不会继承父进程的任何消息通知注册。
当一个进程执行了exec()或终止时,所有打开的描述符会被关闭。在相应队列上的通知注册也会注销

关闭

#include
int mq_close(mqd_t mqdes); 0 SECCESS -1 ERROR

关闭并不会删除。

删除

#include
int mq_unlink(const char *name);0 SECCESS -1 ERROR

会将队列标记为在所有进程使用完该队列之后销毁该队列

特性

struct mq_attr{
	long mq_flags;//0或者O_NONBLOCK
	long mq_maxmsg;
	long mq_msgize;
	long mq_curmsgs;//当前在队列中消息数量
}

在使用mq_open()创建消息队列时
mq_maxmsg字段定义了使用mq_send()向消息队列添加消息的数量上限 其值必须大于0
mq_msgsize字段定义了加入消息队列的每条消息的大小上限,值必须大于0
内核会根据这两个值来确定消息队列所需的最大内存量。创建后无法修改

获取/修改消息队列特性

#include
int mq_getattr(mqd_t mqdes,struct mq_attr *attr);

mq_flags其取值只有0_NONBLOCK。这个标记是根据mq_open的oflag来初始化的,可以修改
mq_curmsgs为当前位于队列中的消息数

#include
int mq_setattr(mqd_t mqdes,const struct mq_attr *newattr,struct mq_attr *oldattr);

唯一能修改的只有mq_flags

mq_getattr(mqd,&attr);
attr.mq_flags|=O_NONBLOCK;
mq_setattr(mqd,&attr,NULL);

交换信息

发送信息

#include
int mq_send(mqd_t mqdes,const char*msg_ptr,size_t msg_len,unisgned int msg_prio);

msg_len指定了消息的长度,其值必须小于mq_msgsize,否则会返回EMSGSIZE错误。(可以为0)
每条消息都用有一个非负整数的优先级,通过msg_prio参数指定,0为最低。
如果消息队列已满(到达了mq_maxmsg),那么后续的mq_send()调用会阻塞到队列中存在可用空间或者设置O_NONBLOCK之间调用失败并返回EAGIN错误。

接受信息

#include
ssize_t mq_recive(mqd_t mqdes,char *msg_ptr,size_t msg_len,unsigned int *msg_prio);

将从mqdes引用的消息队列中删除一条优先级最高、存在时间最长的消息并将其放置在msg_ptr所指的缓冲区。msg_len表示缓冲区长度。不管消息多大,msg_len必须大于等于mq_msgsize。否则会调用失败并返回EMSGSIZE错误。

消息通知

POSIX消息队列能够接受之前为空的队列上有可用消息的异步通知(队列从空变成非空)

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

注意:
在任何一个时刻都只能有一个进程向特定的进程注册通知。如果已经有进程注册,则会返回EBUSY错误
只有当一条新消息进入为空的队列,注册进程才会接到通知(0->1)
当向注册进程发送一个通知后就会删除注册信息
注册进程只有在当前不存在其他在该队列上调用mq_recive()而发生阻塞的进程时才会收到通知。如果其他进程在阻塞,那么该进程会读取消息,注册进程保持注册状态
一个进程可以通过调用mq_notify()时传入一个值为NULL的notification参数来撤销注册

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);
	void *sigev_notify_attributes;
};

sigev_notify会被置为如下

SIGEV_NONE 不通知进程
SIGEV_SIGNAL
通过sigev_signo字段中指定的信号来通知进程。如果sigev_signo是一个实时信号,那么sigev_value字段将会指定信号外带数据。通过传入信号处理器的siginfo_t结构中的si_value字段或通过调用sigwaitinfo()返回值能够取得这部分数据。
SIGEV_THREAD
通过调用在sigev_notify_function中指定的函数来通知进程,就像在新的线程中启动该函数。sigev_notify_attributes字段可以为NULL或指向线程的特性pthread_attr_t结构的指针。sigev_value中指定的联合sigval值将会作为参数传入这个函数。

《Linux/Unix系统编程手册》

你可能感兴趣的:(Linux/Unix系统编程,linux)