信号是UNIX下常见的进程间通信机制。今天碰到一道信号方面题目,与大家分享,题目如下:
用fork创建两个子进程,调用signal()让父进程接收键盘上的中断信号(control-c),捕捉到信号后父进程用kill()向子进程发送自定义信号,子进程捕捉到信号后分别输出如下信息后终止:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
父进程等待两个子进程结束后,输出如下信息后终止:
Parent process is killed!
现给出如下程序:
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
void waiting();
void stop();
static int wait_mark;
int main(int argc, const char *argv[])
{
int p1, p2;
int stdout;
while ((p1 = fork()) == -1);
if (p1 > 0)
{
while ((p2 = fork()) == -1);
if (p2 > 0)
{
wait_mark = 1;
signal(SIGINT, &stop);
waiting();
kill(p1, 16);
wait(0);
kill(p2, 17);
wait(0);
printf("Parent process is killed!\n");
exit(0);
}
else
{
wait_mark = 1;
signal(17, stop);
waiting();
lockf(stdout, 1, 0);
printf("Child process 2 is killed by parent!\n");
lockf(stdout, 0, 0);
exit(0);
}
}
else
{
wait_mark = 1;
signal(16, stop);
waiting();
lockf(stdout, 1, 0);
printf("Child process 1 is killed by parent!\n");
lockf(stdout, 0, 0);
exit(0);
}
return 0;
}
void waiting()
{
while (wait_mark != 0);
}
void stop()
{
wait_mark = 0;
}
可以看到,应用程序运行后,在按下键盘control-c后显示
Parent process is killed!就返回了shell。为什么没有显示应该显示的另外两句呢?
通过调试发现,父进程在接收到control-c,发送消息给子进程让子进程结束的时候,子进程就已经结束掉了,原因是子进程也接收到了control-c的按键并且默认结束了自己,也就是子进程并不是因为父进程发送信号通知自己结束而结束的,而是自己接收到的SIGINT使得自己结束的。那么要得到正确的输出就很简单,可以这么做:
在子进程中把一个空函数注册为处理信号SIGINT的函数,这样子进程接收了到control-c还可以继续运行。
/* 定义一个空函数 */
void blank()
{
/* do nothing */
}
在子进程创建好后:
signal(SIGINT, blank);
重新编译运行程序,就可以得到正确结果了。
$ gcc a.c
$ ./a.out
^CChild process 1 is killed by parent!
Child process 2 is killed by parent!
Parent process is killed!
那么,假如不允许修改原来的程序,也要打印出正确结果怎么办呢?
方法也很简单,原来的程序之所以不能正确输出结果是因为两个子进程也接收到了control-c,因为这个按键是我们在shell里发送给程序的,解决的办法就是单独给父进程的发送SIGINT。
首先编译原来的程序:
$ gcc b.c
运行生成的可执行文件:
$ ./a.out
然后打开一个新的shell,找出所有的a.out。
$ ps -e | grep 'a.out'
3147 pts/0 00:00:01 a.out
3148 pts/0 00:00:01 a.out
3149 pts/0 00:00:01 a.out
发现有三个a.out在运行,一般情况下数字小的就是父进程,也就是这里的3147,我们给这个进程单独发送SIGINT:
$ kill -s INT 3147
再切换回原来的shell,可以看到进程已经被终止了并且输出了正确结果:
Child process 1 is killed by parent!
Child process 2 is killed by parent!
Parent process is killed!