信号: SIGCHILD

本文深入探讨了SIGCHILD信号的默认处理及其显式忽略的原因,并对比了signal与sigaction函数的区别,解析了可再入函数的概念及注意事项。

信号: SIGCHILD

Q:
1 : 该信号默认处理是忽略? 为什么需要显式的忽略?
2: 可移植的信号处理?
3: signal  函数和sigaction 函数的区别
4:可再入
5:

A:
1:  对于信号SIGCHILD 处理, 是在应用中处理的比较多的两个应用(SIGCHILD, SIGPIPE)
   系统默认是忽略该信号的,如果要再捕捉该信号,参考《CSAPP》第八章。

总结: SIGCHLD信号是一个很特殊的信号, 在不同的系统中可能有不同的语意
SIG_DEF (忽略) 和SIG_IGN 在早期的系统中还是有区别的。 如果显式的设置为SIG_IGN, 子进程就可能不会产生僵尸进程。 《APUE》 10.3

2:我们不同的系统中,对信号处理函数signal的理解不一样(比如一个被中断的慢速系统调用是否重启或者永久放弃,在不同的系统中理解是不一样的),
如果我们使用SIGACTION函数, 这样可以明确的告诉系统是否重启慢系统调用。  尽量使用sigaction 函数,为了显式的阻塞信号,使用SIGPROCMASK系列函数
 
3:signal函数只是一次起作用,如果调用了signal函数,下次调用的时候,不能够确定他的信号的处理方式,因为如果signal函数改变了系统的默认处理方式,
 下一次调用的时候可能又设置会默认处理方式了  ,而sigaction函数却是能够一直起作用的。 所以还是用sigaction比较好。 《apue》 第十章。

4:可再入函数 《 apue》上面说的非常清楚, 标志的I/0函数不是可载入函数, 还有就是errno是一个全局的变量, 在信号处理函数中最好首先保存, 最后还原 。
  有以下3中情况函数不是可再如的。 A: 已知他们使用静态数据结构  B: 调用了malloc, free 。 C 他们是标志的I/0函数。
 因为标准i/o库的很多实现都以不可再入的方式使用了全局数据结构。

 


现在重看, 写的不太清楚。 后面继续整理下  , 至少要逻辑清晰
函数 `void handle_sigchild(int sig)` 是一个**信号处理函数**,它在**当进程收到 `SIGCHLD` 信号时被操作系统自动调用**。 --- ### 🔍 调用时机详解: 当你使用 `sigaction()` 或 `signal()` 注册了 `SIGCHLD` 信号的处理函数(如 `handle_sigchild`)后,**每当一个子进程终止、暂停或继续运行时**,操作系统就会向父进程发送 `SIGCHLD` 信号。 这时: > **操作系统会中断当前父进程的执行流程,跳转到你注册的 `handle_sigchild` 函数中执行。** --- ### 🧩 示例说明 你之前注册了: ```c struct sigaction sa = { .sa_handler = handle_sigchild, // 指定处理函数 .sa_flags = SA_RESTART }; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, NULL); ``` 一旦某个子进程退出(或被中断、暂停),操作系统就会: 1. 向父进程发送 `SIGCHLD` 信号; 2. 自动调用 `handle_sigchild()` 函数; 3. 函数内部通过 `waitpid(..., WNOHANG)` 回收子进程; 4. 处理完成后,父进程恢复执行被中断的代码。 --- ### 📌 举个例子: ```c pid_t pid = fork(); if (pid == 0) { // 子进程 sleep(2); exit(0); } else if (pid > 0) { // 父进程 while (1) { printf("Parent is working...\n"); sleep(1); } } ``` 在这个例子中,子进程 2 秒后退出,操作系统会发送 `SIGCHLD` 给父进程,此时: - 父进程正在执行 `sleep(1);` 或 `printf(...)`; - 被中断,跳转到 `handle_sigchild()`; - 执行完处理逻辑后,回到原来的位置继续执行。 --- ### 🧠 注意事项 - `handle_sigchild` 是一个**异步信号处理函数**,不能调用非异步信号安全的函数(如 `printf`、`malloc` 等),否则可能导致未定义行为。 - 推荐在信号处理函数中只做最小化的处理(比如设置标志位),然后在主循环中做实际处理。 --- ### ✅ 改进建议:使用标志位避免不安全函数 ```c volatile sig_atomic_t child_exit = 0; void handle_sigchild(int sig) { child_exit = 1; // 设置标志位 } int main() { // ... 注册信号处理函数 ... while (1) { if (child_exit) { child_exit = 0; // 在这里安全地调用 waitpid 等函数 pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { printf("Child %d exited\n", pid); } } // 主循环其他逻辑 } } ``` --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值