北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

C语言信号处理完全指南:12个核心函数详解

一、什么是信号?生活中的例子理解

想象你在图书馆看书(主程序执行中),突然:

  • 手机震动(SIGINT) 有人发消息
  • 闹钟响了(SIGALRM) 到午餐时间
  • 管理员喊你(SIGTERM) 要闭馆了

信号就是程序执行中的“突发事件”,需要立即响应!


二、12个必会信号函数对照表

函数名

用途

日常比喻

使用场景

signal()

设置信号处理器

给手机设铃声

快速响应信号

sigaction()

高级信号处理

智能手机的情景模式

专业级信号管理

kill()

发送信号

给别人打电话

进程间通信

raise()

给自己发信号

给自己设提醒

程序自我管理

alarm()

定时信号

设闹钟

延时/超时处理

pause()

暂停等待信号

坐等外卖电话

简单信号等待

sigemptyset()

清空信号集合

清空购物车

信号处理前准备

sigaddset()

添加信号到集合

商品加入购物车

批量管理信号

sigprocmask()

屏蔽/恢复信号

开勿扰模式

保护关键代码

sigpending()

获取未处理信号

查看未接来电

诊断信号问题

sigsuspend()

安全等待信号

带防护措施睡觉

高可靠性等待

sigqueue()

发送带数据的信号

寄挂号信

进程间数据传输


三、6大核心函数详解 + 实战代码

1. 基础响应:signal()函数

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

void signal_handler(int sig_num) {
    printf("收到信号: %d\n", sig_num);
}

int main() {
    // 注册Ctrl+C信号处理
    signal(SIGINT, signal_handler);
    
    printf("按下Ctrl+C试试...\n");
    while(1) {
        sleep(1);
    }
    return 0;
}

效果:按下Ctrl+C打印信号数字(通常是2)而不退出程序

2. 专业处理:sigaction()函数

struct sigaction sa;

void handler(int sig) {
    printf("专业处理信号 %d\n", sig);
}

int main() {
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask); // 清空屏蔽集
    sa.sa_flags = SA_RESTART; // 被中断后自动重启
    
    // 设置SIGTERM处理器
    sigaction(SIGTERM, &sa, NULL);
    
    printf("请用命令 kill %d 测试\n", getpid());
    while(1) pause();
}

3. 定时功能:alarm()+ pause()组合

#include <unistd.h>

void alarm_handler(int sig) {
    printf("闹钟响了!该吃午饭了!\n");
}

int main() {
    signal(SIGALRM, alarm_handler);
    
    // 设置5秒闹钟
    alarm(5);
    printf("设置了5秒闹钟(等待中)...\n");
    
    pause(); // 等待闹钟信号
    return 0;
}

4. 信号屏蔽:sigprocmask()保关键

sigset_t block_set;

int main() {
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGINT); // 屏蔽Ctrl+C
    
    printf("== 关键操作开始 ==\n");
    sigprocmask(SIG_BLOCK, &block_set, NULL); // 开启屏蔽
    
    // 这里不会被Ctrl+C中断
    for(int i=0; i<3; i++) {
        printf("关键操作 %d/3\n", i+1);
        sleep(1);
    }
    
    sigprocmask(SIG_UNBLOCK, &block_set, NULL); // 解除屏蔽
    printf("== 关键操作结束 ==\n");
    
    return 0;
}

5. 信号通信:kill()进程交互

// receiver.c
int main() {
    signal(SIGUSR1, signal_handler);
    printf("接收端PID: %d\n", getpid());
    pause();  // 等待信号
}
// sender.c
int main(int argc, char** argv) {
    if(argc < 2) {
        printf("用法: %s <接收PID>\n", argv[0]);
        return 1;
    }
    pid_t pid = atoi(argv[1]);
    kill(pid, SIGUSR1);  // 发送信号
    printf("已向进程%d发送信号\n", pid);
}

6. 带数据传输:sigqueue()高级通信

// 发送数据方
union sigval value;
value.sival_int = 12345; // 发送整型数据
sigqueue(receiver_pid, SIGUSR1, value);

// 接收处理函数
void handler(int sig, siginfo_t* info, void* ucontext) {
    printf("收到带数据的信号!值=%d\n", info->si_value.sival_int);
}

四、实用项目示例:定时任务管理器

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

void execute_task(int task_id) {
    printf("执行任务 #%d\n", task_id);
}

void timer_handler(int sig) {
    static int counter = 0;
    execute_task(++counter);
    alarm(3); // 每3秒重复
}

int main() {
    struct sigaction sa;
    sa.sa_handler = timer_handler;
    sigaction(SIGALRM, &sa, NULL);
    
    // 启动3秒定时器
    alarm(3); 
    
    printf("定时任务启动...\n");
    while(1) pause();  // 永久等待信号
}

五、信号处理黄金法则

处理要简单:Handler中只做标记,复杂操作回主程序

原子操作:全局变量用volatile sig_atomic_t

安全第一:volatile sig_atomic_t flag = 0; // 安全 // int flag = 0; // 危险

避开禁地:void handler() { printf("危险操作"); // 绝对禁止 malloc(100); // 地狱之门 }


六、特殊信号百科全书

信号

触发场景

能否捕获

SIGINT

2

Ctrl+C

SIGQUIT

3

Ctrl+\

SIGTERM

15

kill默认

SIGKILL

9

kill -9

强制

SIGSTOP

19

Ctrl+Z

强制

SIGSEGV

11

段错误

SIGUSR1

10

用户自定义

SIGUSR2

12

用户自定义

SIGALRM

14

alarm()

SIGCHLD

17

子进程终止


七、多进程/线程最佳实践

// 父进程等待子进程结束
void sigchld_handler(int sig) {
    pid_t pid;
    while((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
        printf("子进程 %d 已结束\n", pid);
    }
}

int main() {
    // 防止子进程变僵尸
    struct sigaction sa;
    sa.sa_handler = sigchld_handler;
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    sigaction(SIGCHLD, &sa, NULL);
    
    // 创建子进程
    if(fork() == 0) {
        printf("子进程 %d 工作中...\n", getpid());
        sleep(2);
        exit(0);
    }
    
    // 父进程继续工作
    while(1) {
        printf("父进程工作中...\n");
        sleep(1);
    }
}

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言