Linux应用编程—12.信号
信号用于内核层与应用层之间、应用层与应用层之间传递控制指令。在终端下面通过键盘输入“Ctrl + C”就是向操作系统发送了一个控制指令,告诉系统结束当前进程。
在终端下输入“kill -l”即可查看系统支持的所以控制指令。如下图1所示。
如图所示,一共有64个指令。经常使用的“Ctrl + C”就是9号:SIGINT指令,用来结束当前进程。如果父子进程同时运行,在中断下输入“Ctrl + C”只能终止父进程,子进程还在运行。这种情况,我们可以通过控制指令“kill”来结束这个子进程。
查看控制指令“kill”的说明。
NAME
kill - send a signal to a process
SYNOPSIS
kill [options] <pid> [...]
DESCRIPTION
The default signal for kill is TERM. Use -l or -L to list available
signals. Particularly useful signals include HUP, INT, KILL, STOP,
CONT, and 0. Alternate signals may be specified in three ways: -9,
-SIGKILL or -KILL. Negative PID values may be used to choose whole
process groups; see the PGID column in ps command output. A PID of -1
is special; it indicates all processes except the kill process itself
and init.
kill指令的作用是发送一个信号到进程。默认情况下这个kill信号是结束进程“TERM”。假如结束进程id号为:7436的进程。在在中断下输入:kill 7436即可。
12.1 signal()函数用来改变信号的处理
函数原型,sighandler_t signal(int signum, sighandler_t handler);其中handler是函数指针,typedef void (*sighandler_t)(int);当触发了某一个信号,会去执行handler入口的函数。原本“SIGINT”的默认功能是结束当前进程,但是如果使用signal()函数重新处理后,当触发到“SIGINT”后,转去执行handler函数,覆盖了以前的功能。设计这样一段程序,使用signal()函数重新改写SIGINT,当键盘输入“Ctrl + C”后,打印字符串“SIGINT triged.”,然后代码每隔1秒钟打印计数值一次。为了方便后续终止这个进程,打印当前进程id号,供终端关闭该进程。
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void function(int signl);
int main(void)
{
int i = 0;
signal(SIGINT, function);
printf("Process pid = %d\n.", getpid());
while(1)
{
printf("Count to %d.\n", ++i);
sleep(1);
}
return 0;
}
void function(int signl)
{
printf("SIGINT triged.\n");
}
运行结果:
当用户输入“Ctrl + C”时,没有结束当前进程,计数继续,并且打印SIGINT triged.代码运行符合预期。结束当前进程可以通过另一个终端输入:kill 10773.结果如下图3所示:
改写代码,使之具有之前的功能——结束当前进程,只需在被触发调用的函数后面加上一个退出即可。exit(1)。修改后代码如下:
void function(int signl)
{
printf("SIGINT triged.\n");
exit(1);
}
运行结果如下:
12.2 kill()函数
kill()函数是向一个进程发送信号。函数原型如下:int kill(pid_t pid, int sig);入参分别是进程id号pid与信号。返回值,成功:0;失败:-1。
编写一段代码,通过main()函数入参传入进程id号,并且代码中通过调用kill()函数将这个进程终止。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int *argc, char *argv[])
{
kill(atoi(argv[1]), SIGKILL);
return 0;
}
通过gcc编译为KILL 可执行文件,
在终端启动上一个代码,代码正常运行,并且打印进程id号:11099,在另一个终端中执行:./KILL 11099,11099的进程结束。运行结果如下图5所示:
12.3 总结
信号用于内核层与应用层、应用层与应用层之间传递控制指令。Linux下有64种信号类型。使用signal()函数可以改写信号的作用,但有的信号不支持。kill()函数可以向一个进程发送某个信号。