读书笔记:第5章 Posix消息队列 (6)

《UNIX网络编程:卷2》P73:图5-12

-------------------------------------------------------------------

/*
 * mqnotifysig3.c
 * P73 图5-12 使用信号通知读Posix消息队列
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <mqueue.h>

static void sig_usr1(int signo);

volatile sig_atomic_t	mqflag;		// 有信号处理程序置为1

int main(int argc, char *argv[])
{
	mqd_t		mqd;
	void		*buff;
	ssize_t		n;
	sigset_t	zeromask, newmask, oldmask;
	struct mq_attr	attr;
	struct sigevent	sigev;

	if (argc != 2) {
		fprintf(stderr, "usage: mqnotifysig1 <name>\n");
		exit(0);
	}

	// 打开一个消息队列,非阻塞模式读取消息队列
	if ((mqd = mq_open(argv[1], O_RDONLY | O_NONBLOCK)) < 0) {
		fprintf(stderr, "mq_open error: %s\n", strerror(errno));
		exit(1);
	}

	// 获取消息队列的属性
	mq_getattr(mqd, &attr);

	// 分配缓冲区
	if ((buff = malloc(attr.mq_msgsize)) == NULL) {
		fprintf(stderr, "malloc error: %s\n", strerror(errno));
		exit(1);
	}

	sigemptyset(&zeromask);				// 初始化信号集
	sigemptyset(&newmask);
	sigemptyset(&oldmask);
	sigaddset(&newmask, SIGUSR1);		// 在newmask中打开SIGUSR1的位

	// 建立信号处理程序
	signal(SIGUSR1, sig_usr1);
	sigev.sigev_notify = SIGEV_SIGNAL;	// 队列由空变为非空时,产生信号
	sigev.sigev_signo = SIGUSR1;		// 希望产生的信号编号

	//  为指定队列建立异步通知
	if (mq_notify(mqd, &sigev) < 0) {
		fprintf(stderr, "mq_notify error: %s\n", strerror(errno));
		exit(1);
	}

	for ( ; ; ) {
		sigprocmask(SIG_BLOCK, &newmask, &oldmask);		// 阻塞SIGUSR1,并把当前信号掩码保存到oldmask中

		while (mqflag == 0)
			sigsuspend(&zeromask);		// 原子性的将调用线程投入睡眠,并把它的信号掩码复位成zeromask
		mqflag = 0;

		// 当通知被发送给它的注册进程时,其注册被撤销,所以再次注册 
		if (mq_notify(mqd, &sigev) < 0) {
			fprintf(stderr, "mq_notify error: %s\n", strerror(errno));
		}

		// 从消息队列中取出消息,使用循环
		while ((n = mq_receive(mqd, buff, attr.mq_msgsize, NULL)) >= 0) {
			printf("SIGUSR1 received, read %ld types\n", n);
		}
		if (errno != EAGAIN)			// EAGAIN,意味着暂时没有消息可读
			fprintf(stderr, "mq_receive error\n");

		sigprocmask(SIG_UNBLOCK, &newmask, NULL);		// 解除阻塞
	}

	exit(0);
}

static void sig_usr1(int signo)
{
	mqflag = 1;
	return;
}

运行程序:

$ ./mqcreate /test1
$ ./mqnotifysig3 /test1

从另一个窗口中运行:

$ ./mqsend /test1 50 16

程序mqnotifysig3输出为:

SIGUSR1 received, read 50 types

这个可以解决前一个例子的问题。

第一个变动是打开消息队列时指定O_NONBLOCK标志;另一个变动是在循环中调用mq_receive,处理消息队列中的每个消息。

你可能感兴趣的:(读书笔记,《UNIX网络编程》)