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还没有释放对一些互斥资源的所有权造成死锁。