1. 信号概述
在Linux系统中,信号是一种用于进程间通信和控制进程行为的机制。信号可以被用来通知进程发生了某个特定的事件,比如用户按下了某个键,或者其他进程发送了信号。同时,信号也可以用来中断正在运行的进程,并将控制权转移给信号处理函数。
信号可以被认为是一种事件,它可以被发送到一个进程,然后由该进程处理。不同的信号有不同的意义和行为。在Linux系统中,每个信号都有一个唯一的名称和一个编号。每个信号可以由编号来标识,也可以使用信号名称来标识。
2. 常用信号
下面是一些常用的信号:
2.1 SIGHUP
SIGHUP信号是挂起控制终端或者控制进程结束时发送给进程的信号。当接收到该信号时,进程通常需要重新加载配置文件和重新初始化。
2.2 SIGINT
SIGINT信号是由终端驱动器发送给前台进程的中断信号。用户可以通过在终端上按下Ctrl+C来发送该信号。接收到SIGINT信号的进程通常会中断当前的操作。
2.3 SIGTERM
SIGTERM信号是由系统发送给进程的终止信号。该信号用于请求进程正常终止,进程可以选择在接收到SIGTERM信号后做一些清理工作。
2.4 SIGKILL
SIGKILL信号是由系统发送给进程的强制终止信号。与SIGTERM不同,SIGKILL信号将会立即终止进程,进程没有机会做任何清理工作。
除了上面提到的信号,Linux系统还支持很多其他的信号,每个信号都有其独特的含义和行为。
3. 信号处理
Linux系统提供了一系列函数来处理信号:
3.1 signal()
signal()函数用于设置信号处理函数。它的原型如下:
#include <signal.h>
void (*signal(int sig, void (*handler)(int)))(int);
signal()函数接收两个参数:
sig:要设置的信号。
handler:信号处理函数的地址。
信号处理函数的原型为:
void handler(int sig);
信号处理函数需要接收一个整型参数,该参数为信号的编号。信号处理函数可以是一个自定义函数,也可以是系统提供的预定义函数,比如SIG_IGN(忽略信号)或SIG_DFL(默认行为)。
3.2 sigaction()
sigaction()函数也用于设置信号处理函数,它比signal()函数功能更强大。它的原型如下:
#include <signal.h>
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oldact);
sigaction()函数接收三个参数:
sig:要设置的信号。
act:一个struct sigaction类型的结构体,用于设置信号处理函数和其他信号处理相关的选项。
oldact:一个struct sigaction类型的结构体,用于保存之前的信号处理函数和选项。
sigaction()函数相对于signal()函数的优势在于它提供了更多的选项,比如可以指定信号处理函数的行为(执行一次还是多次)、在信号处理函数执行期间是否屏蔽其他信号等。
4. 使用注意事项
在处理信号时,需要注意以下几点:
信号处理函数应尽可能的简洁,以避免阻塞其他信号的传递。
信号处理函数应尽量避免对全局变量和静态变量的访问,以避免竞争条件的发生。
进程会在接收到某个信号后从用户态切换到内核态,执行信号处理函数。在信号处理函数执行完成后,进程会在原来的位置继续执行。
在多线程程序中,每个线程都有自己独立的信号掩码。默认情况下,信号掩码中的所有信号都会被阻塞。可以使用pthread_sigmask()函数来修改信号掩码。
总结来说,了解并掌握系统信号相关的重要指令对于理解和掌握Linux系统的控制权至关重要。信号在进程间通信和控制进程行为中起着重要的作用,我们可以通过设置信号处理函数来实现对信号的处理和操作。在实际应用中,我们需要根据需求合理设置信号处理函数,并注意处理函数的编码规范和使用注意事项,以保证程序的正确性和稳定性。