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

《UNIX网络编程:卷2》P70:图5-9

/*
 * mqnotifysig1.c
 * P70 图5-9 当有消息放置到某个空队列中时产生SIGUSR1(不正确版本)
 */
#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);

mqd_t   mqd;
void    *buff;
struct mq_attr  attr;
struct sigevent sigev;

int main(int argc, char *argv[])
{
    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);
    }   

    // 建立信号处理程序
    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 ( ; ; ) 
        pause();

    exit(0);
}

static void sig_usr1(int signo)
{
    ssize_t n;

    // 当通知被发送给它的注册进程时,其注册被撤销,所以再次注册 
    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);
    return;
}

运行程序:

$ ./mqcreate /test1
$ ./mqnotifysig1 /test1

从另一个窗口中运行:

$ ./mqsend /test1 50 16

程序mqnotifysig1输出为:

SIGUSR1 received, read 50 types

验证每次只有一个进程可以被注册为接收通知,从另一个窗口启动该程序:

$ ./mqnotifysig1 /test1
mq_notify error: Device or resource busy

该程序的问题是它从信号处理程序中调用mq_notify、mq_receive和printf。这些函数实际上都不可以从信号处理程序中调用。

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