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

《UNIX网络编程:卷2》P72:图5-11

/*
 * mqnotifysig2.c
 * P72 图5-11 信号处理程序只是给主线程设置一个标志(不正确版本)
 */
#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)) < 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));
		}

		// 从消息队列中取出消息
		n = mq_receive(mqd, buff, attr.mq_msgsize, NULL);
		printf("SIGUSR1 received, read %ld types\n", n);

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

	exit(0);
}

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

运行程序:

$ ./mqcreate /test1
$ ./mqnotifysig2 /test1

从另一个窗口中运行:

$ ./mqsend /test1 50 16

程序mqnotifysig2输出为:

SIGUSR1 received, read 50 types

这种办法仍然存在问题。如果在能够读出第一个消息之前有两个消息到达,那么只有一个通知被发出。原因是:通知只是在有一个消息被放置到某个空队列时才发出。

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