UNIX IPC: POSIX 消息队列 与 信号

POSIX消息队列可以注册空队列有消息到达时所触发的信号,而信号触发对应的信号处理函数。

下面是一份基本的消息队列和信号处理结合的代码(修改自UNIX网络编程:进程间通信)

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <signal.h>
#include <pthread.h>


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

static void sig_user1(int signo) {
    printf("current pid:%d, threadid:%u\n", getpid(), pthread_self());
    int n, prio;
    /*     signal will be unregistered from previous registered message queue 
        when first message arrived.
        So register signal again if we want trigger the signal handler again */
    mq_notify(queue, &sigev);
    
    /* read msg */
    int res = mq_receive(queue, buff, attr.mq_msgsize, &prio);
    if (res < 0) {
        perror("receive msg fail");
        exit(-1);
    }
    printf("prio: %d, msg: %s\n", prio, (char*)buff);
    return;
}

int main(int argc, char** argv) {
    char* name = "/testmq";
    if (argc > 0) {
        name = argv[1];
    }

    queue = mq_open(name, O_RDONLY);

    if (queue < 0) {
        perror("open message queue fail");
        return -1;
    }

    int res = mq_getattr(queue, &attr);
    if (res != 0) {
        perror("get message queue fail");
        return -1;
    }

    buff = malloc(attr.mq_msgsize);

    signal(SIGUSR1, sig_user1);

    sigev.sigev_notify = SIGEV_SIGNAL;
    sigev.sigev_signo = SIGUSR1;

    mq_notify(queue, &sigev);

    printf("[%d.%d] start to waiting\n", getpid(), pthread_self());
    for (;;) {
        pause();
    }

    return 0;
}

 

运行输出:

hgf@ubuntu:~/ipc$ ./mqnotify /haha
[25328.1410565952] start to waiting
current pid:25328, threadid:1410565952

可以看到主线程和执行信号处理的线程是同一个,这估计也是书上说以上程序存在问题,因为有些函数调用不应该放在信号处理函数当中。因为它们可能使用了互斥资源可能造成死锁,比如printf,当其正在处理时又来一个信号于是再次调用printf然后可能上一个printf还没有释放对一些互斥资源的所有权造成死锁。

posted @ 2015-03-06 14:59  卖程序的小歪  阅读(256)  评论(0编辑  收藏  举报