C语言信号处理完全指南

信号是 Unix/Linux 系统中进程间通信的一种异步机制。本文将详细介绍 C 语言中的信号处理机制、常见函数与最佳实践。

什么是信号?

信号是一种软中断,用于通知进程发生了某个事件。常见信号包括:

  • SIGINT (Ctrl+C) - 终端中断信号
  • SIGTERM - 终止信号(优雅退出)
  • SIGKILL - 强制终止信号(不可捕获)
  • SIGSEGV - 段错误信号
  • SIGALRM - 定时器信号

signal() 函数

最简单的信号处理方式是用 signal() 函数注册处理函数:

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

void handle_sigint(int sig) {
    printf("\n收到 SIGINT 信号,正在安全退出...\n");
    /* 注意:这里不能调用不安全的函数 */
}

int main(void) {
    /* 注册 SIGINT 信号处理函数 */
    signal(SIGINT, handle_sigint);

    printf("按 Ctrl+C 退出程序\n");
    while (1) {
        sleep(1);
    }
    return 0;
}

sigaction() 函数

推荐使用 sigaction(),它比 signal() 更可靠且可移植性更好:

sigaction_demo.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>

static sigjmp_buf jump_buffer;
volatile sig_atomic_t jump_ok = 0;

void sigalarm_handler(int sig) {
    if (jump_ok)
        siglongjmp(jump_buffer, 1);
}

int main(void) {
    struct sigaction sa;
    sa.sa_handler = sigalarm_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGALRM, &sa, NULL);

    if (sigsetjmp(jump_buffer, 1) == 0) {
        jump_ok = 1;
        alarm(3);
        printf("等待 3 秒超时...\n");
        sleep(10);
    } else {
        printf("超时!跳回执行\n");
    }

    return 0;
}

信号处理的安全准则

在信号处理函数中必须注意以下几点:

  1. 使用异步信号安全函数 - 只能调用 async-signal-safe 的函数,如 write()、_exit(),不能调用 printf()、malloc() 等
  2. 设置全局标志 - 在处理函数中只设置标志位,在主程序中处理实际逻辑
  3. 使用 sig_atomic_t - 对于布尔标志,使用 sig_atomic_t 类型确保原子操作
  4. 注意可重入性 - 避免在信号处理函数中访问可能被中断的代码使用的数据

常见应用场景

1. 超时处理

使用 alarm() 和 sigaction() 实现操作超时:

timeout_demo.c
/* 简化版超时处理 */
void timeout_handler(int sig) {
    /* 设置全局超时标志 */
    timeout_flag = 1;
}

/* 在需要超时的操作前设置定时器 */
alarm(5);  /* 5秒后触发 SIGALRM */

2. 优雅退出

处理 SIGTERM 实现优雅退出:

graceful_exit.c
volatile sig_atomic_t running = 1;

void sigterm_handler(int sig) {
    running = 0;  /* 收到信号后退出主循环 */
}

/* 主循环中检查标志 */
while (running) {
    /* 处理业务 */
}
/* 清理资源并退出 */
cleanup();

总结

信号处理是 C 语言系统编程中的重要内容。使用 sigaction() 而非 signal(),遵循异步信号安全准则,可以写出健壮可靠的多线程/多进程程序。