You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux信号问题:自定义SIGINT信号处理函数为何仅生效一次?

问题原因与解决方法

核心原因

你使用的signal函数属于传统UNIX信号机制,它有一个关键特性:当信号处理函数被触发执行一次后,系统会自动将该信号的处理动作重置为默认行为(SIG_DFL)。因此第一次Ctrl+C触发handler2执行后,SIGINT的处理方式变回默认的终止进程,第二次发送SIGINT时就直接退出了。

这种设计是早期UNIX的遗留行为,目的是让开发者手动决定是否重新注册信号处理逻辑,但它的行为在不同系统中可能存在差异,属于“不可靠信号”的范畴。

解决办法

方法1:在处理函数内重新注册信号

在handler2内部再次调用signal,重新绑定处理函数,确保下次收到信号时仍能触发自定义逻辑:

void handler2(int sig)
{
  int olderrno = errno;
  // 重新注册SIGINT的处理函数
  if (signal(SIGINT, handler2) == SIG_ERR)
    unix_error("signal re-registration error");
  Sio_puts("Handler in ");
  Sio_putl(getpid());
  Sio_puts("\n");
  errno = olderrno;
}

注意:这种方式存在竞态条件——如果在重新注册完成前再次收到SIGINT,仍会触发默认终止行为。

方法2:使用标准可靠的sigaction函数

sigaction是POSIX标准定义的信号处理接口,行为明确且跨平台一致,默认不会自动重置处理动作。替换signal函数即可解决问题:

#include "csapp.h"

void handler2(int sig)
{
  int olderrno = errno;
  Sio_puts("Handler in ");
  Sio_putl(getpid());
  Sio_puts("\n");
  errno = olderrno;
}

int main()
{
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = handler2;
  // 可选:添加SA_RESTART让被信号中断的系统调用(如Sleep)自动重启
  // sa.sa_flags = SA_RESTART;
  if (sigaction(SIGINT, &sa, NULL) == -1)
    unix_error("sigaction error");

  while (1)
  {
    printf("Parent %d\n", (int)getpid());
    Sleep(5);
  }
  return 0;
}

推荐使用这种方式,它是现代Linux系统中处理信号的标准方案,避免了传统signal的行为不确定性。

内容的提问来源于stack exchange,提问作者elivon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 19:16:04