15) SIGTERM
kill命令的默认方式就是发出SIGTERM信号,在终端输入kill +PID即可给指定PID的进程发送该信号,测试程序如下:
1 /** 2 * filename: signal_15.c 3 * author: Suzkfly 4 * date: 2021-02-18 5 * platform: Ubuntu 6 * 操作步骤: 7 * 运行可执行程序,记住打印出来的PID的值,另开一个终端,输入kill +PID命令, 8 * 观察打印结果。 9 */ 10 #include <stdio.h> 11 #include <signal.h> 12 #include <unistd.h> 13 14 /* 自定义信号处理函数 */ 15 void func(int sig) 16 { 17 switch (sig) { 18 case SIGTERM : 19 printf("SIGTERM signal captured. value = %d\n", sig); 20 break; 21 } 22 } 23 24 int main(int argc,char *argv[]) 25 { 26 void(*p)(int) = NULL; 27 28 p = signal(SIGTERM, func); 29 if (p == SIG_ERR) { 30 printf("signal failed\n"); 31 } 32 33 printf("PID = %d\n", getpid()); 34 35 while (1) { 36 sleep(1); 37 } 38 39 return 0; 40 }
测试结果:
(该图白线上部分与下部分是两个不同的终端)
16) SIGSTKFLT
man手册中对该信号的描述是这样的:Stack fault on coprocessor (unused),翻译过来就是:协处理器上的堆栈异常(未使用)。首先协处理器的堆栈异常,具体是哪种异常没说,另外手册上写的未使用,那就算出现了协处理器堆栈异常它也不一定能引发该信号。
17) SIGCHLD
该信号由子进程停止(stopped)或者终止时产生,实际上子进程从停止态转变为运行态也会引发SIGCHIL信号。进行该项测试需要知道两个命令,一是让进程进入停止态,使用kill -STOP +PID,二是让进程从停止态变回运行态,使用kill -CONT +PID。
测试程序如下:
1 /** 2 * filename: signal_17.c 3 * author: Suzkfly 4 * date: 2021-02-18 5 * platform: Ubuntu 6 * 操作步骤:另开1个终端,根据子进程打印出来的PID值,可以使用kill -9 +PID杀 7 * 死子进程,也可以使用kill -STOP +PID,让子进程进入停止态,使用 8 * kill -CONT +PID让进程继续运行,观察打印结果。 9 */ 10 #include <stdio.h> 11 #include <signal.h> 12 #include <unistd.h> 13 14 /* 自定义信号处理函数 */ 15 void func(int sig) 16 { 17 switch (sig) { 18 case SIGCHLD : 19 printf("SIGCHLD signal captured. value = %d\n", sig); 20 break; 21 } 22 } 23 24 int main(int argc,char *argv[]) 25 { 26 int pid = 0; 27 void(*p)(int) = NULL; 28 29 pid = fork(); 30 if (pid > 0) { /* 父进程 */ 31 p = signal(SIGCHLD, func); 32 if (p == SIG_ERR) { 33 printf("signal failed\n"); 34 } 35 36 while (1) { 37 printf("I'm parent PID = %d\n", getpid()); 38 sleep(5); 39 } 40 } else if (pid == 0) { /* 子进程 */ 41 while (1) { 42 printf("I'm child PID = %d\n", getpid()); 43 sleep(5); 44 } 45 } 46 47 return 0; 48 }
操作过程:
执行程序,能看到父进程和子进程每隔5秒打印他们自己的PID,另开1个终端,使用kill -STOP命令让子进程停止,这时父进程将收到SIGCHLD信号,子进程进入STOP状态,再执行kill -CONT命令可以让子进程恢复,此时父进程还会收到SIGCHLD信号,使用kill -9杀死子进程,父进程依然能收到SIGCHLD信号。
执行结果:
18,19) SIGCONT,SIGSTOP
SIGCONT信号是所有信号中唯一一个默认动作为让进程继续运行的信号,正常情况下要让进程继续运行就应该先让进程进入停止态,但是实际上即使进程正在运行也可以给他发送SIGCONT信号,在信号17中已经说过,可以用kill -STOP +PID让进程进入停止态,使用kill -CONT +PID命令让进程继续运行,实际上kill -STOP +PID命令就是给进程发送SIGSTOP信号,而kill -CONT +PID命令就是给进程发送SIGCONT信号。需要注意的是SIGSTOP信号不能被忽略、阻塞已经自定义处理方法。
测试程序如下:
1 /** 2 * filename: signal_18.c 3 * author: Suzkfly 4 * date: 2021-03-14 5 * platform: Ubuntu 6 * 操作步骤:运行程序,另开1个终端,根据进程打印出来的PID值,使用 7 * kill -STOP +PID,让子进程进入停止态,使用 8 * kill -CONT +PID让进程继续运行,观察打印结果。 9 */ 10 #include <stdio.h> 11 #include <signal.h> 12 #include <unistd.h> 13 14 /* 自定义信号处理函数 */ 15 void func(int sig) 16 { 17 switch (sig) { 18 case SIGCONT : 19 printf("SIGCONT signal captured. value = %d\n", sig); 20 break; 21 } 22 } 23 24 int main(int argc,char *argv[]) 25 { 26 int pid = 0; 27 void(*p)(int) = NULL; 28 29 p = signal(SIGCONT, func); 30 if (p == SIG_ERR) { 31 printf("signal failed\n"); 32 } 33 34 while (1) { 35 printf("PID = %d\n", getpid()); 36 sleep(5); 37 } 38 39 return 0; 40 }
测试结果:
注意事项:
在测试时发现一个很奇怪的问题,当一个进程被kill -STOP命令变为停止态之后再用kill -CONT命令变为运行态,此时该进程用Ctrl+C或者用Ctrl+\都无法终止,而使用kill -INT命令可以使其终止,这说明一个进程被kill -STOP命令变为停止态之后再用kill -CONT命令变为运行态之后,它并不是收不到信号或者对Ctrl+C等Ctrl+\忽略,而是Ctrl+C和Ctrl+\按键产生不了SIGINT信号和SIGQUIT信号了,其原因尚不明确。