一、什么是信号
在 Linux 中,信号是一种用于通知进程发生了某种事件的机制。信号可以由内核、其它进程或者命令行工具发送给目标进程。Linux 系统中由多种信号,每种信号都用一个唯一的数值表示。例如,常见的信号如下:
SIGINT (2)
:这是当用户在终端按下 Ctrl+C 时发送给前台进程的信号,通常用于请求进程终止。SIGKILL (9)
:这是一种强制终止进程的信号,它会立即终止目标进程,且不能被捕获或忽略。SIGTERM (15)
:这是一种用用户请求进程终止的信号,通常由系统管理员或其它进程发送给目标进程。SIGUSR1 (10)
和SIGUSR2 (12)
:这两个信号是用户自定义的信号,可以由应用程序使用。SIGSEGV (11)
:这是一种表示进程非法内存访问的信号,通常是由于进程尝试访问未分配的内存或者视图访问非法指令而导致的。SIGALRM (14)
:这是一个定时器信号,通常用于在一定时间间隔后向目标进程发送信号。
每种信号都有特定的含义和行为,进程可以通过注册信号处理函数来捕获信号并执行相应的操作。如果想要查看所有的 Linux 信号,可以执行 kill -l
指令,会的到以下反馈。
二、注册信号处理
我们可以使用通过 signal
系统调用注册信号处理函数。
typedef void (*__sighandler_t) (int);/*** @brief 注册信号处理函数* * @param __sig 要处理的信号* @param __handler 当收到对应的信号时,要调用的函数* @return __sighandler_t 返回之前的信号处理函数,如果错误返回SEG_ERR*/
__sighandler_t signal (int __sig, __sighandler_t __handler);
signal()
系统调用会注册某一信号对应的处理函数。如果注册成功,当进程收到这一信号时,将不会调用默认的处理函数,而是调用这里的自定义处理函数。
三、信号处理例程
我们新建一个 main.c 文件。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>void sigint_handler(int signum);int main(void)
{if (signal(SIGINT, sigint_handler) == SIG_ERR){perror("register signal error!");exit(EXIT_FAILURE);}while (1){sleep(1);printf("wait for Ctrl+C to stop the signal.\n");}return 0;
}void sigint_handler(int signum)
{printf("receive %d signal.\n", signum);exit(signum);
}
我们在终端中使用 gcc 编译程序,生成可执行文件,然后运行它。
gcc main.c -o main
./main