Linux Linux程序练习十六(进程间的通信信号版)
/* * 题目: * 编写程序,要去实现如下功能: 父进程创建子进程1和子进程2、子进程1向子进程2发送可靠信号,并传送额外数据为子进程1的pid*2; 子进程2接受可靠信号的值,并发送给父进程,父进程把接受的值进行打印。 提示:用sigqueue和sigaction实现 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> /* * 父进程中,知道所有子进程的pid,所以父进程向子进程1发送带数据的信号,数据是子进程2的pid * 子进程1向子进程2发送信号,子进程2向父进程发送信号 * */ //子进程1信号安装回调函数 void handler1(int sign, siginfo_t * info, void *p) { if (sign == SIGRTMIN) { printf("子进程1接收到父进程发送的数据:子进程2的pid=%d\n", info->si_value.sival_int); //向子进程2发送带数据的信号 union sigval v1; v1.sival_int = getpid() * 2; if (sigqueue(info->si_value.sival_int, SIGRTMIN,v1) != 0) { perror("sigqueue() err"); return; } //退出子进程1 printf("子进程1 quit\n"); exit(0); } printf("子进程1接收到其他信号"); } //子进程2信号安装回调函数 void handler2(int sign, siginfo_t * info, void *p) { if (sign == SIGRTMIN) { printf("子进程2接收到数据%d\n", info->si_value.sival_int); //向父进程发送信号 if (sigqueue(getppid(), SIGRTMIN, info->si_value) != 0) { perror("sigqueue() err"); return; } //退出子进程2 printf("子进程2 quit\n"); exit(0); } } //父进程信号安装回调函数 void handlerf(int sign, siginfo_t * info, void *p) { if (sign == SIGRTMIN) { //打印信号值 printf("父进程接收的值是%d\n", info->si_value.sival_int); printf("game is over!\n"); exit(0); } } int main(int arg, char *args[]) { pid_t pid = 0; pid = fork(); if (pid == -1) { perror("fork() err"); return -1; } if (pid == 0) { //子进程1 printf("子进程1的pid=%d\n",getpid()); //安装信号SIGRTMIN,等待父进程发送信号 struct sigaction act; act.sa_sigaction = handler1; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; if (sigaction(SIGRTMIN, &act, NULL) != 0) { printf("sigaction() failed !\n"); exit(0); } //等待父进程发送信号 printf("子进程1等待父进程发送信号\n"); while (1) { printf("子进程1 sleep\n"); sleep(1); } } if (pid > 0) { //存储子进程1的pid pid_t pid_1 = pid; pid = fork(); if (pid == -1) { perror("fork() err"); exit(0); } if (pid == 0) { //子进程2 printf("子进程2的pid=%d\n",getpid()); //安装信号SIGRTMIN,等待子进程1发送信号 struct sigaction act; act.sa_sigaction = handler2; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; if (sigaction(SIGRTMIN, &act, NULL) != 0) { printf("sigaction() failed !\n"); exit(0); } //等待子进程1发送信号 printf("子进程2等待子进程1发送信号\n"); while (1) { printf("子进程2 sleep\n"); sleep(1); } } else if (pid > 0) { //父进程 printf("父进程的pid=%d\n",getpid()); //安装信号SIGRTMIN,等待子进程2发送信号 struct sigaction act; act.sa_sigaction = handlerf; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; if (sigaction(SIGRTMIN, &act, NULL) != 0) { printf("sigaction() failed !\n"); exit(0); } sleep(5); //向子进程1发送信号 printf("父进程向子进程1发送信号\n"); union sigval v1; v1.sival_int = pid; if (sigqueue(pid_1, SIGRTMIN, v1) != 0) { perror("sigqueue() err"); exit(0); } int ret = 0; //等待子进程退出 while (1) { ret = wait(NULL); if (ret == -1) { if (errno == EINTR) { continue; } break; } } //等待信号到达 while (1) { sleep(1); } } } return 0; } /* * 错误总结:执行该程序,发现子进程1老是出不来,开始我以为是fork()失败,经过注释代码调试 * 发现问题出现在父进程的发送信号这个函数上,原因是父进程发送信号的时候,,子进程1刚被创建,还没有执行安装信号函数 * 而信号SIGRTMIN的默认行为是终止进程,所以子进程刚被创建好了,就被终止了 * * 实际上还有一种方法,可以在fork()之前安装3个不同的信号,3个进程分别接收不同的信号加以处理 * */