嵌入式Linux:进程如何处理信号

2026-10-043

在 Linux 系统中,进程收到信号后,可以选择忽略信号、捕获信号并执行自定义处理函数,或执行系统默认操作。Linux 主要通过 signal() 和 sigaction() 设置信号处理方式。

signal() 函数

函数原型

#include <signal.h>
typedef void (*sig_t)(int);
sig_t signal(int signum, sig_t handler);
  • signum 指定信号,可使用 SIGINT 等名称。
  • handler 是处理函数指针,也可以设置为 SIG_IGN(忽略)或 SIG_DFL(默认处理)。
  • 成功时返回之前的处理函数指针;失败返回 SIG_ERR 并设置 errno。

下面的示例捕获 SIGINT,打印信号编号后继续运行:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static void handle_signal(int signal) {
    printf("Caught signal %d\n", signal);
}

int main(void) {
    signal(SIGINT, handle_signal);

    while (1) {
        printf("Running...\n");
        sleep(1);
    }
}

如果希望忽略 SIGINT,可以把注册语句改为 signal(SIGINT, SIG_IGN)。

sigaction() 函数

sigaction() 比 signal() 提供更细的控制和更好的可移植性,实际开发中通常优先使用它。

函数原型

#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
             struct sigaction *oldact);

signum 不能是 SIGKILL 或 SIGSTOP;act 描述新的处理方式,oldact 用于保存旧配置,不需要时可传 NULL。成功返回 0,失败返回 -1 并设置 errno。

结构体中的关键成员:

  • sa_handler:普通处理函数、SIG_IGN 或 SIG_DFL。
  • sa_sigaction:带额外上下文的处理函数,需要配合 SA_SIGINFO。
  • sa_mask:处理函数执行期间临时阻塞的信号集合。
  • sa_flags:控制行为,例如 SA_RESTART、SA_NODEFER 和 SA_SIGINFO。

下面的示例使用 SA_SIGINFO 获取发送进程的 PID:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static void handle_signal(int signal, siginfo_t *info, void *context) {
    (void)context;
    printf("Caught signal %d\n", signal);
    printf("Signal sent by process %d\n", info->si_pid);
}

int main(void) {
    struct sigaction act = {0};
    act.sa_sigaction = handle_signal;
    act.sa_flags = SA_SIGINFO;
    sigemptyset(&act.sa_mask);

    sigaction(SIGINT, &act, NULL);

    while (1) {
        printf("Running...\n");
        sleep(1);
    }
}

注意事项

进程没有显式设置处理方式时,通常使用系统默认动作。通过 fork() 创建子进程时,子进程会继承父进程的信号处理配置,但也可以在后续运行中重新设置。

信号处理函数应尽量短小,只执行设置标志、记录简单状态等必要操作。复杂逻辑放在主循环中处理,可以减少重入、竞争条件和全局状态不一致的风险。

来源:嵌入式Linux:进程如何处理信号(CSDN,原作者“不脱发的程序猿”,CC BY-SA 4.0)

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -