【IPC通信】Posix消息队列使用非阻塞mq_receive的信号通知

落花浮王杯 提交于 2019-12-06 09:33:00

某个空的消息队列被放置一个消息时通过产生一个信号通知进程,进程取走消息。

#include <stdio.h>
#include <stdlib.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>

volatile sig_atomic_t mqflag; // 被信息处理函数设置为非0值
void sig_usr1(int);

int main(int argc, char *argv[])
{
    mqd_t mqd;
    char *ptr;
    struct mq_attr attr;
    struct sigevent sigev;
    sigset_t zeromask, newmask, oldmask; // 信号集
    unsigned int prio;
    size_t n;
    int rc;

    if(argc != 2)
    {
        printf("Usage: mqnotifysig3 <name>\n");
        exit(1);
    }

    /*只读模式打开消息队列,同时指定非阻塞标志*/
    mqd = mq_open(argv[1], O_RDONLY);
    if(mqd < 0)
    {
        perror("打开消息队列失败");
        exit(1);
    }

    
    /*取得消息队列属性*/
    rc = mq_getattr(mqd, &attr);
    if(rc < 0)
    {
        perror("取得消息队列属性失败");
        exit(1);
    }

    /*动态申请保证能存放单条消息的内存*/
    ptr = calloc(attr.mq_msgsize, sizeof(char));
    if(NULL == ptr)
    {
        printf("动态申请内存失败\n");
        mq_close(mqd);
        exit(1);
    }

    /*初始化信号集*/
    if(sigemptyset(&zeromask) < 0) {perror("初始化信号集失败");}
    if(sigemptyset(&newmask) < 0) {perror("初始化信号集失败");}
    if(sigemptyset(&oldmask) < 0) {perror("初始化信号集失败");}
    if(sigaddset(&newmask, SIGUSR1) < 0) {perror("添加SIGUSR1信号失败");}

    //注册信号函数
    signal(SIGUSR1, sig_usr1);
    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGUSR1;

    //注册通知
    rc = mq_notify(mqd, &sigev); // 读取前需要再次注册
    if(rc < 0)
    {
        perror("通知注册失败");
        mq_close(mqd);
        free(ptr);
        exit(1);
    }

    for(;;)
    {
        if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0 ) {perror("阻塞信号失败");}
        while(0 == mqflag)
        {
            sigsuspend(&zeromask); /*等待信号到来*/
        }
        mqflag = 0;
        
        rc = mq_notify(mqd, &sigev); // 读取前需要再次注册
        if(rc < 0)
        {
            perror("通知注册失败");
            mq_close(mqd);
            free(ptr);
            exit(1);
        }

        while((n = mq_receive(mqd, ptr, attr.mq_msgsize, &prio)) >= 0)
        {
            printf("Read %ld bytes\nPrio: %d\n", n, prio);
        }
        if(EAGAIN != errno)
        {
            perror("读取失败");
        }

        sigprocmask(SIG_UNBLOCK, &newmask, NULL);
    }
    exit(0);
}

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

编译并执行:

[infor@s123 PosixMq]$ gcc -o mqnotifysig3 mqnotifysig3.c -lrt
[infor@s123 PosixMq]$ ./mqnotifysig3 /tmp

程序阻塞在此处,等待其他进程向消息队列写入消息。

另开一个会话,调用之前的写消息程序:

[infor@s123 PosixMq]$ ./sendmq /tmp 100 10
[infor@s123 PosixMq]$ ./sendmq /tmp 90 9

可以看到消息被读了出来:

[infor@s123 PosixMq]$ gcc -o mqnotifysig3 mqnotifysig3.c -lrt
[infor@s123 PosixMq]$ ./mqnotifysig3 /tmp
Read 100 bytes
Prio: 10
Read 90 bytes
Prio: 9

2011-11-21  任洪彩 qdurenhongcai@163.com

转载请注明出处。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!