Kill() 和 Signal() 注意事项

0. 背景

最近学习操作系统的时候,遇到一个题目

编写程序:用 fork( )创建两个子进程,再用系统调用 signal( )让父进程捕捉键盘上来的中断信号(即按^c 键);捕捉到中断信号后,父进程用系统调用 kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:

Child process1 is killed by parent!

Child process2 is killed by parent!

父进程等待两个子进程终止后,输出如下的信息后终止:

Parent process is killed!

1. 问题

编写的时候,发现:

  1. 父进程无法重写 SIGKILL 信号的处理函数。
  2. 子进程无法捕获主动发送的 SIGUSR1 信号。

2. 尝试寻找答案

2.1 问题 1

经过一番搜索后,发现原因是:

The signals SIGKILL and SIGSTOP cannot be caught or ignored.

From: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html

也就是说,SIGKILL 和 SIGSTOP 信号是无法被捕获或忽略的。

因此,只能使用 SIGINT/SIGUSR1 信号来代替。

2.2 问题 2

经过多次思考与尝试,发现子进程无法捕获主动发送的 SIGUSR1 信号,原因是:

SIGINT 信号会比 SIGUSR1 信号优先被处理,因此,子进程无法捕获到 SIGUSR1 信号。

3. 解决方案

3.1 问题 1

既然 SIGKILL 信号无法被捕获或忽略,那么我们只能使用 SIGINT 信号来代替。

3.2 问题 2

既然 SIGINT 信号会比 SIGUSR1 信号优先被处理,那么我们只要注册一个空的 SIGINT 信号处理函数即可。

4. 代码

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int subprocess1, subprocess2;
void killChild1(int a)
{
printf("Child process1 is killed by parent!\n");
exit(0);
}

void killChild2(int a)
{
printf("Child process2 is killed by parent!\n");
exit(0);
}

void parentInterrupt()
{
kill(subprocess1,SIGUSR1);
kill(subprocess2,SIGUSR1);
wait(NULL);
wait(NULL);
printf("Parent process is killed!\n");
exit(0);
}

void doNotHandle(int a)
{
return;
}

int main()
{
subprocess1 = fork();
if(subprocess1 != 0)
{
//parent
subprocess2 = fork();
if(subprocess2 != 0)
{
//parent
signal(SIGINT,parentInterrupt);

while(1);
} else {
//sub2
signal(SIGUSR1,killChild2);
signal(SIGINT,doNotHandle);
while(1);
}
} else {
//sub1
signal(SIGUSR1,killChild1);
signal(SIGINT,doNotHandle);
while(1);
}
return 0;
}

效果如图:

/img/Signal/1.png


Kill() 和 Signal() 注意事项
https://nacldragon.top/2023/Signal/
作者
NaCl
发布于
2023年8月21日
许可协议