当前位置:首页 > 系统教程 > 正文

Linux进程信号:信号的保存与处理 (从入门到实践)

Linux进程信号:信号的保存与处理 (从入门到实践)

对于初学者来说,Linux进程信号可能是一个抽象的概念,但它是进程间通信和异常处理的核心机制。本文将详细讲解信号的保存与处理,帮助你彻底理解这一重要主题。

什么是信号?

信号是Linux系统中的一种软件中断,用于通知进程某个事件已经发生。例如,按下Ctrl+C会向前台进程发送SIGINT信号,默认终止进程。信号可以来自键盘、硬件异常(如段错误)、其他进程或内核自身。

信号的三种处理方式

  • 默认动作:系统预定义的行为,如终止、停止或忽略。
  • 忽略信号:进程明确表示不处理该信号。
  • 自定义处理:通过signal()sigaction()注册用户函数,当信号到达时执行该函数。

信号的保存:阻塞与未决

在信号递达(实际执行处理)之前,内核会为每个进程维护两个重要的信号集:阻塞信号集(信号屏蔽字)和未决信号集。这就是信号保存的核心概念。

  • 未决信号集:记录当前进程收到了哪些信号,但尚未处理。每个信号对应一个标志位,0表示未收到,1表示收到但未处理。
  • 阻塞信号集:记录当前进程暂时不处理的信号(即被阻塞的信号)。如果一个信号在阻塞集中,即使它处于未决状态,也不会递达,直到阻塞解除。

进程可以使用sigprocmask()来修改阻塞信号集,用sigpending()获取未决信号集。例如,以下代码阻塞了SIGINT

sigset_t newmask, oldmask;sigemptyset(&newmask);sigaddset(&newmask, SIGINT);sigprocmask(SIG_BLOCK, &newmask, &oldmask);  // 阻塞SIGINT
Linux进程信号:信号的保存与处理 (从入门到实践) Linux进程信号 信号保存 信号处理 信号阻塞 第1张

信号的处理:捕捉与递达

当信号解除阻塞后,会从未决状态变为递达状态,执行相应的处理动作。这里涉及信号处理的关键函数:signal()sigaction()sigaction()更强大,支持信号传递额外信息。下面是一个自定义处理SIGUSR1的例子:

#include #include #include void handler(int sig) {    printf("收到信号 %d", sig);}int main() {    struct sigaction sa;    sa.sa_handler = handler;    sigemptyset(&sa.sa_mask);    sa.sa_flags = 0;    sigaction(SIGUSR1, &sa, NULL);    while(1) pause();  // 等待信号    return 0;}

注意,在处理信号期间,如果设置了sa_mask,这些信号会被自动阻塞,防止嵌套处理。

信号阻塞与未决的综合示例

下面的流程展示了信号阻塞如何影响未决状态:

  1. 进程阻塞SIGINT
  2. 用户按下Ctrl+C,内核向进程发送SIGINT,此时未决信号集中对应位置1。
  3. 由于信号被阻塞,处理函数不会立即执行。
  4. 进程调用sigprocmask解除SIGINT的阻塞。
  5. 内核检查未决信号集,发现有SIGINT未处理,于是将其递达,执行自定义或默认动作。

总结

理解Linux进程信号的保存与处理,对于编写健壮的Linux程序至关重要。通过阻塞信号集和未决信号集,进程可以灵活地控制信号何时到达、如何处理。希望本文能帮助小白读者迈出掌握信号机制的第一步。

关键词:Linux进程信号、信号保存、信号处理、信号阻塞