071. 理解C语言中的信号处理

在C语言中,信号处理是一种用于处理异步事件(如用户中断、硬件异常等)的机制。信号是一种软件中断,当某些事件发生时,操作系统会向进程发送信号。进程可以捕获这些信号,并通过信号处理函数来响应这些事件。

1. 信号的基本概念

信号是进程间通信的一种方式,用于通知进程某些事件的发生。信号可以由硬件异常、用户操作(如键盘中断)、系统调用等触发。每个信号都有一个唯一的编号(如SIGINTSIGSEGV等)。

2. 常见的信号

  • SIGINT:用户通过键盘输入中断字符(如Ctrl+C)时发送。

  • SIGSEGV:发生段错误(如访问非法内存)时发送。

  • SIGTERM:请求终止进程时发送。

  • SIGKILL:强制终止进程时发送。

  • SIGQUIT:用户通过键盘输入退出字符(如Ctrl+\)时发送。

  • SIGALRM:定时器到期时发送。

3. 信号处理函数

信号处理函数是一个用户定义的函数,当特定信号发生时,操作系统会调用这个函数。可以通过signalsigaction函数设置信号处理函数。

使用signal函数

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

// 信号处理函数
void handleSignal(int sig) {
    printf("捕获信号:%d\n", sig);
}

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

    printf("等待信号...\n");
    while (1) {
        sleep(1); // 休眠1秒
    }

    return 0;
}

使用sigaction函数

sigaction函数比signal更灵活,提供了更多的控制选项。

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

// 信号处理函数
void handleSignal(int sig) {
    printf("捕获信号:%d\n", sig);
}

int main() {
    struct sigaction sa;

    // 设置信号处理函数
    sa.sa_handler = handleSignal;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGINT, &sa, NULL);

    printf("等待信号...\n");
    while (1) {
        sleep(1); // 休眠1秒
    }

    return 0;
}

4. 信号的默认行为

每个信号都有一个默认的行为,例如:

  • SIGINT:终止进程。

  • SIGSEGV:终止进程并生成核心转储文件。

  • SIGTERM:终止进程。

  • SIGKILL:强制终止进程,无法捕获或忽略。

5. 忽略信号

可以通过将信号处理函数设置为SIG_IGN来忽略某些信号。

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

int main() {
    // 忽略SIGINT信号
    signal(SIGINT, SIG_IGN);

    printf("等待信号...\n");
    while (1) {
        sleep(1); // 休眠1秒
    }

    return 0;
}

6. 阻塞信号

可以通过sigprocmask函数阻塞某些信号,防止它们在特定时间内被处理。

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

// 信号处理函数
void handleSignal(int sig) {
    printf("捕获信号:%d\n", sig);
}

int main() {
    sigset_t set;

    // 初始化信号集
    sigemptyset(&set);
    sigaddset(&set, SIGINT);

    // 阻塞SIGINT信号
    sigprocmask(SIG_BLOCK, &set, NULL);

    // 注册信号处理函数
    signal(SIGINT, handleSignal);

    printf("等待信号...\n");
    while (1) {
        sleep(1); // 休眠1秒
    }

    return 0;
}

7. 信号的优缺点

优点

  • 灵活性:可以自定义信号处理逻辑。

  • 实时性:信号可以异步触发,及时响应某些事件。

缺点

  • 复杂性:信号处理可能导致代码复杂化,难以维护。

  • 线程安全:在多线程程序中,信号处理需要特别小心,避免竞态条件。

  • 不可靠性:某些信号(如SIGKILL)无法捕获或忽略。

8. 总结

信号处理是C语言中一种强大的机制,用于处理异步事件。通过使用signalsigaction函数,可以设置信号处理函数,捕获并响应特定信号。合理使用信号处理可以提高程序的健壮性和响应能力,但需要注意信号处理的复杂性和线程安全问题。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)