02 Posix 消息队列

1. 基本特性
  • 消息队列可以认为是一个消息链表,有足够权限的线程可以往队列里放消息,有足够读权限的线程可以从队列中读取消息。每个消息时一个记录,并且有一个优先级
  • 一个进程向消息队列写入消息之前,并不需要某个进程在该队列上等待该消息的到达,而管道和FIFO如果没有读者就开始写,则会产生SIGPIPE信号
  • 管道和FIFO是随进程的持续性,当管道和FIFO最后一次关闭发生时,仍在管道和FIFO中的数据会被丢弃。
    消息队列是随内核的持续性,即一个进程向消息队列写入消息后,然后终止,另外一个进程可以在以后某个时刻打开该队列读取消息。只要内核没有重新自举,消息队列没有被删除。
2. API介绍
2.1 创建或打开一个队列:mq_open
// oflag: O_CREAT,O_EXCL,O_WRONLY, O_RDONLY,O_RDWR, O_NONBLOCK
mqd_t mq_open(const char *name, int oflag, ... /*mode_t mode, struct mq_attr *attr*/);
	// 成功返回队列描述符,失败返回-1

#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <fcntl.h>

#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main()
{
	// /tmp.123 为文件系统中的消息队列名,linux默认在目录/dev/mqueue下
	mqd_t mqdes = mq_open("/tmp.123", O_RDWR | O_CREAT, FILE_MODE, NULL); 
	if (mqdes == -1) {
		printf("create mqdes fail\n");
		return -1;
	}
	mq_close(mqdes); // 参数为消息队列描述符,close并不会删除文件系统中的消息队列
	return 0;
}
2.2 关闭队列:mq_close
int mq_close(mqd_t mqdes);
    // 参数为队列描述符,成功返回0,失败返回-1

mq_close用于关闭一个消息队列,和文件的close类型,关闭后,消息队列并不从系统中删除。一个进程结束,会自动调用关闭打开着的消息队列。

2.3 删除队列:mq_unlink
int mq_unlink(const char *name);
	// 参数为消息队列名,成功返回0,失败返回-1
#include <stdio.h>
#include <mqueue.h>
#include <fcntl.h>

int main()
{
	if (mq_unlink("/tmp.123") == -1) {
		printf("mq_unlink fail\n"); // 参数为文件系统中的消息队列名
		return -1;
	}
	return 0;
}

1)mq_unlink用于删除一个消息队列。消息队列创建后只有通过调用该函数或者是内核自举才能进行删除。 unlink后,需要所有引用该消息队列的进程都close才会真正销毁该消息队列
2)LInux将消息队列描述符实现成了文件描述符,因此在linux下可以用select、poll、epoll来操作消息队列描述符。linux将消息队列挂接在虚拟文件系统中,也可以用rm进行删除

2.4 队列的attr参数:mq_attr
struct mq_attr {
	long mq_flags; // 阻塞标志  mq_setattr设置
	long mq_maxmsg;  // 队列中最大的个数  open时指定
	long mq_msgsize;  // 每个消息的最大字节数  open时指定
	long mq_curmsgs; // 当前队列中的消息数 只能读取
};
mq_setattr可以设置的属性只有mq_flags,用来设置或清除消息队列的非阻塞标志。
mq_maxmsg和mq_msgsize属性只能在创建消息队列时通过mq_open来设置
mq_curmsgs属性只能被获取而不能被设置。
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); // 设置消息队列的属性参数

#include<stdio.h>
#include<string.h>
#include<mqueue.h>
#include<fcntl.h>

#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
// 设置消息队列的额外参数
int main()
{
	mq_attr attrSet;
	attrSet.mq_msgsize = 128; // 指定消息队列每个消息的最大长度
	attrSet.mq_maxmsg = 10; // 指定消息队列的最大消息个数
	mqd_t mqdes = mq_open("/tttmp.111", O_CREAT | O_RDWR, FILE_MODE, &attrSet); // 在open时设置
	if (mqdes == -1) {
		printf("mq_open error\n");
		return -1;
	}
	
	char buf[128];
	sprintf(buf, "xxxxx");
	if (mq_send(mqdes, buf, strlen(buf), 1) == -1)
	{
		printf("sned fail\n");
		return -1;
	}
	
	mq_attr attr;
	mq_getattr(mqdes, &attr);
	printf("%d, %d, %d, %d\n", attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
	
	mq_close(mqdes);
	return 0;
}
	

// 获取消息队列额外参数
int main()
{
	mqd_t mqdes = mq_open("/tttmp.111", O_CREAT | O_RDWR, FILE_MODE, NULL);
	if (mqdes == -1) {
		printf("mq_open error\n");
		return -1;
	}
	mq_attr attr;
	mq_getattr(mqdes, &attr);
	printf("%d, %d, %d, %d", attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
	
	mq_close(mqdes);
	mq_unlink("/tttmp.111");
	return 0;
}
2.5 向队列添加消息:mq_send
// 发送的内容为ptr,个数为len,优先级为prio
int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio); 
	 // 成功返回0,失败返回-1
#include<stdio.h>
#include<string.h>
#include<mqueue.h>
#include<fcntl.h>

#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main()
{
	mq_attr attrSet;
	attrSet.mq_msgsize = 128;
	attrSet.mq_maxmsg = 10;
	mqd_t mqdes = mq_open("/tttmp.111", O_CREAT | O_RDWR, FILE_MODE, &attrSet);
	if (mqdes == -1) {
		printf("mq_open error\n");
		return -1;
	}
	
	char buf[128];
	sprintf(buf, "xxxxx");
	if (mq_send(mqdes, buf, strlen(buf), 1) == -1) // 消息队列描述符,需要发送的buf,buf长度,优先级
	{
		printf("sned fail\n");
		return -1;
	}
	
	mq_attr attr;
	mq_getattr(mqdes, &attr);
	printf("%d, %d, %d, %d\n", attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
	
	mq_close(mqdes);
	return 0;
}
	

2.6 接收队列中的消息:mq_receive
// 接受的buf为ptr,buf消息len不小于attr中的mq_msgsize,接收到的消息优先级为priop
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop); // 成功返回读取的字节数,失败返回-1

#include<stdio.h>
#include<string.h>
#include<mqueue.h>
#include<fcntl.h>

#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main()
{
	mqd_t mqdes = mq_open("/tttmp.111", O_RDONLY, FILE_MODE, NULL);
	if (mqdes == -1) {
		printf("mq_open error\n");
		return -1;
	}
	
	mq_attr attr;
	mq_getattr(mqdes, &attr);
	unsigned int prip;
	printf("%d, %d, %d, %d\n", attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
	char buf[128];
	while (mq_receive(mqdes, buf, sizeof(buf), &prip) != -1)
	{
		printf("%s\n", buf);
		memset(buf, 0, sizeof(buf));
	}
	mq_close(mqdes);
	return 0;
}
2.7 消息队列由空变有时的异步消息通知:mq_notify
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;
};
// notification非空时注册异步通知函数,为空时且当前进程之前被注册为接收通知的进程则撤销注册
// 1. 只有一个进程能被注册 2. 只有由空变有的时候通知 
// 3. 只有队列没有被阻塞为receive时由空变有才会通知(阻塞优先级高) 4. 每次通知后就清除注册信息
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
2.8 其他

1)两个限制
MQ_PRIO_MAX 消息最大优先级
MQ_OPEN_MAX 一个进程最多能打开的消息队列数量。

#include<stdio.h>
#include<string.h>
#include<mqueue.h>
#include<fcntl.h>
#include	<sys/types.h>
#include	<unistd.h>

int main(int argc, char **argv)
{
	printf("MQ_OPEN_MAX = %ld, MQ_PRIO_MAX = %ld\n",
		sysconf(_SC_MQ_OPEN_MAX), sysconf(_SC_MQ_PRIO_MAX));
		
	return 0;
}

总结下
sigsuspend
sigwait
sigwaitinfo
sigtimewait
==》信号API介绍


参考:
https://blog.csdn.net/anonymalias/article/details/9799645
https://www.2cto.com/kf/201608/542972.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值