🧩 一、信号的捕获(Signal Handling)
在用户空间,信号的捕获依靠系统调用 signal() 或更强大的 sigaction() 实现。
1️⃣ 使用 signal() 捕获信号
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int sig) {
    printf("Caught signal %d\n", sig);
}
int main() {
    signal(SIGINT, handler); // 捕获 Ctrl+C
    while (1) pause();
    return 0;
}
👉 缺点:signal() 的行为在不同 UNIX 实现中不完全一致。
2️⃣ 使用 sigaction()
推荐使用 sigaction(),它提供更强的控制能力:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int sig) {
    printf("Handled signal %d\n", sig);
}
int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);
    while (1) pause();
}
- sa_mask:表示在执行信号处理函数时要额外阻塞的信号集。
- sa_flags:可控制信号行为,如- SA_RESTART自动重启被中断的系统调用。
🧱 二、信号阻塞与信号集(Signal Mask)
有时我们需要**暂时屏蔽(阻塞)**某些信号,防止在关键代码段中被打断。
1️⃣ 使用 sigprocmask()
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_BLOCK, &set, NULL);
该代码阻塞 SIGINT 信号,直到调用:
sigprocmask(SIG_UNBLOCK, &set, NULL);
2️⃣ 检查当前阻塞信号集
sigset_t pending;
sigpending(&pending);
if (sigismember(&pending, SIGINT))
    printf("SIGINT is pending\n");
⚙️ 三、信号的发送
除了内核自身发送信号外,进程也可主动发送信号:
| 函数 | 用途 | 
|---|---|
| kill(pid, sig) | 向指定进程发送信号 | 
| raise(sig) | 向当前进程发送信号 | 
| pthread_kill(thread, sig) | 向线程发送信号(多线程专用) | 
示例:
kill(getpid(), SIGUSR1);
🚀 四、实时信号(Real-Time Signals)
Linux 从 POSIX.1b 标准起引入了实时信号(Real-time Signals),范围通常是:
SIGRTMIN ~ SIGRTMAX (一般为 32~64)
与普通信号的区别:
| 项目 | 普通信号 | 实时信号 | 
|---|---|---|
| 是否排队 | 否(可能丢失) | 是(可排队多个) | 
| 传递顺序 | 不确定 | 按发送顺序 | 
| 附带数据 | 无 | 可携带整型或指针数据 | 
使用示例(通过 sigqueue() 发送带数据的信号):
union sigval val;
val.sival_int = 42;
sigqueue(pid, SIGRTMIN, val);
接收端:
void handler(int sig, siginfo_t *info, void *context) {
    printf("Got value: %d\n", info->si_value.sival_int);
}
🧭 五、总结与最佳实践
| 场景 | 推荐做法 | 
|---|---|
| 简单信号捕获 | 使用 sigaction() | 
| 防止临界区被打断 | 使用 sigprocmask()阻塞 | 
| 进程通信(轻量) | 使用 kill() | 
| 进程通信(带数据) | 使用 sigqueue()与实时信号 | 
| 多线程环境 | 使用 pthread_sigmask()与pthread_kill() | 
发表回复