C Academy · 课时

信号

异步通知

第 4 / 4 课13 个步骤

信号 是 CoddyKit 上的免费 C Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

什么是信号

信号是发送给进程的异步通知,用于告知进程某个事件已经发生,例如用户按下 Ctrl-C 或子进程退出。信号是一种轻量级 IPC 形式。

常见信号

您经常会遇到以下几种信号:

  • SIGINT 中断(Ctrl-C)
  • SIGTERM 礼貌的终止请求
  • SIGKILL 强制终止(无法捕获)
  • SIGCHLD 子进程状态发生变化
  • SIGSEGV 无效的内存访问

默认处理方式

每个信号都有一个默认操作:终止、终止并生成核心转储、忽略、停止或继续。您可以通过处理函数覆盖其中的大多数默认操作。

安装处理函数

设置处理函数的现代、可移植方式是使用 sigaction。处理函数是一个接收信号编号的函数。

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

void on_signal(int sig) {
    /* note: printf is not async-signal-safe; for demo only */
    write(1, "caught\n", 7);
}

int install(void) {
    struct sigaction sa = {0};
    sa.sa_handler = on_signal;
    return sigaction(SIGINT, &sa, NULL);
}

为什么不使用 signal()

旧的 signal() 函数在不同系统上的行为并不一致(处理函数会被重置,且无法控制 SA_RESTART)。请优先使用定义明确且可移植的 sigaction。

异步信号安全函数

处理函数可能在代码执行的任意时刻打断程序,因此只能调用 异步信号安全的函数,例如 write。在处理函数中调用 printf 或 malloc 可能导致死锁或数据损坏。

使用 volatile 标志

一种安全的模式是:处理函数设置一个 volatile sig_atomic_t 标志,主循环对其进行检查。这样可以让处理函数保持简短且安全。

#include <signal.h>

volatile sig_atomic_t stop = 0;

void handler(int sig) {
    stop = 1; /* only set a flag */
}
/* main loop: while (!stop) { do_work(); } */

发送信号

使用 kill(pid, sig) 向另一个进程发送信号,或使用 raise(sig) 向自身发送信号。尽管名称中有 kill,它可以发送任意信号,而不只是致命信号。

#include <signal.h>

int notify(int pid) {
    return kill(pid, SIGTERM); /* ask process to terminate */
}

阻塞信号

为了保护关键区段,请使用 sigprocmask 和信号集暂时阻塞信号。被阻塞的信号会保持为待处理状态,并在解除阻塞后送达。

#include <signal.h>

void block_int(void) {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);
}

使用 SIGCHLD 回收子进程

子进程退出时,内核会发送 SIGCHLD。调用 waitpid 的处理函数会回收子进程,防止产生一直留在进程表中的僵尸进程。

#include <signal.h>
#include <sys/wait.h>

void reap(int sig) {
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ; /* reap all finished children */
}

无法捕获的信号

有两个信号是绝对的:SIGKILL 始终终止进程,SIGSTOP 始终停止进程。它们无法被捕获、阻塞或忽略,为系统提供了控制进程的可靠方式。

快速检查

测试您对信号的理解。

回顾

您已经学习了如何使用信号进行异步通知。

  • 使用 sigaction 而不是旧的 signal 安装处理函数
  • 处理函数必须是异步信号安全的;最好只设置一个标志
  • 使用 kill/raise 发送信号;使用 sigprocmask 阻塞信号
  • 收到 SIGCHLD 时回收子进程;SIGKILL 和 SIGSTOP 无法被捕获
免费开始

用 AI 导师学习 C — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
39
课程
144

常见问题解答

「信号」课时是免费的吗?

是的 — 「信号」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「信号」这节课中我会学到什么?

异步通知 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「信号」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 管道
  2. 共享内存
  3. 消息队列
  4. 信号
← 返回 C Academy