信号是操作系统中一种重要的通信机制,它允许进程之间通过发送软件中断来传递信息,从而实现异步事件的处理。信号提供了进程间通信(IPC)的一个基本手段,允许系统或进程在特定事件发生时通知另一个进程。在Unix/Linux系统中,信号的定义和管理通过
signal.h
头文件进行,总共定义了62个信号,分为不可靠的非实时信号(前31个)和可靠的实时信号(后31个)两大类。
信号的处理方式
忽略信号
并非所有信号都能被忽略,如SIGKILL
(9)和SIGSTOP
(19)这两个信号,它们分别用于强制结束进程和停止进程,不能被进程忽略。
默认处理
如果未显式设置信号处理方式,系统将采取默认动作,例如终止进程或忽略信号。
捕获信号
通过自定义信号处理函数,进程可以捕获信号并在特定信号到达时执行预设的代码逻辑,之后再恢复原执行流程。
信号处理流程
当信号到达时,内核会保存当前进程的上下文,执行信号处理函数,处理完成后恢复现场,使进程继续执行原有任务。
//信号处理
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
typedef void (*sighandler_t)(int);
void handler(int signum){
printf("成功捕获%d号信号了!\n",signum);
}
int count = 1;
int main(void){
//这个地方第一次处理(忽略)二号信号,会返回null
sighandler_t ret = signal(SIGINT,SIG_IGN);
if(ret==SIG_ERR){
perror("signal");
return -1;
}
printf("ret = %p\n",ret);
//这里第二次处理二号信号
sighandler_t ret2 = signal(SIGINT,handler);
printf("ret2 = %p\n",ret2);
//sighandler_t ret3 = signal(SIGINT,SIG_IGN);
//printf("ret3 = %p\n",ret3);
for(;;){
printf("当前循环次数%d\n",count++);
sleep(1);
};
return 0;
}
重入问题与信号安全
信号处理函数在执行过程中若遇到自身被再次调用的情况,称为“重入”。这可能导致全局变量、静态变量等共享资源的不一致问题,因为信号处理函数的执行可能会打断对这些资源的正常访问流程。因此,编写信号处理函数时应避免访问全局或静态变量,以保证信号处理的原子性和安全性。
太平间信号:SIGCHLD
当子进程结束时,系统向其父进程发送SIGCHLD
(17)信号,父进程可在信号处理函数中异步回收子进程资源,避免僵尸进程的产生。然而,如果信号处理函数执行时间过长,可能导致后续相同信号的丢失,因为Linux系统默认对重复的实时信号不累积处理。
总结
信号作为一种强大的异步事件处理机制,在Unix/Linux系统编程中扮演着重要角色。通过合理设置信号处理方式,开发者可以有效地响应系统事件、实现进程间通信及管理进程生命周期。然而,信号处理也需谨慎,特别是要关注重入问题和信号处理函数的安全性,以避免潜在的并发问题。