接上一篇:linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数
今天来分享通过SIGCHLD信号来回收子进程,也介绍一下该信号的一些知识点,开始上菜:
此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】
1.SIGCHLD的产生条件
①子进程终止时;
②子进程接收到SIGSTOP信号停止时;
③子进程处在停止态,接受到SIGCONT后唤醒时;
2.借助SIGCHLD信号回收子进程
子进程结束运行,其父进程会收到SIGCHLD信号。该信号的默认处理动作是忽略。可以捕捉该信号,在捕捉函数中完成子进程状态的回收。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
void do_sig_child(int signo)
{
int status;
pid_t pid;
//waitpid:回收子进程
//0 回收和当前调用waitpid一个组的所有子进程
while ((pid = waitpid(0, &status, WNOHANG)) > 0)
{
//为非0,进程正常结束
if (WIFEXITED(status))
{
//获取进程退出状态 (exit的参数)
printf("子进程 %d 退出 %d\n", pid, WEXITSTATUS(status));
}
else if (WIFSIGNALED(status))//为非0,进程异常终止
{
//取得使进程终止的那个x信号的编号。
printf("子进程 %d 取消 信号 %d\n", pid, WTERMSIG(status));
}
}
}
int main(void)
{
pid_t pid;
int i;
for (i = 0; i < 5; i++)
{
//创建子进程
if ((pid = fork()) == 0)
{
break;
}
else if (pid < 0)
{
perror("fork error");
exit(1);
}
}
if (pid == 0)
{
int n = 1;
while (n--)
{
printf("子进程 ID %d\n", getpid());
sleep(1);
}
return i+1;
}
else if (pid > 0)
{
struct sigaction act;
act.sa_handler = do_sig_child;
sigemptyset(&act.sa_mask);//清零信号集合
act.sa_flags = 0;
sigaction(SIGCHLD, &act, NULL);//注册SIGCHLD信号捕捉函数
while (1)
{
printf("父进程 ID %d\n", getpid());
sleep(1);
}
}
return 0;
}
3.子进程结束status处理方式
waitpid函数:
函数作用:
作用同wait,但可指定pid进程清理,可以不阻塞。
头文件:
#include <sys/types.h>
#include <sys/wait.h>
函数原型:
pid_t waitpid(pid_t pid, int *status, in options);
函数参数:
pid:
>0 回收指定ID的子进程,回收指定子进程时,只要该子进程结束,就可回收,回收时间>=子进程结束时间。
-1 回收任意子进程(相当于wait)
0 回收和当前调用waitpid一个组的所有子进程
<-1 回收指定进程组内的任意子进程 可以和kill命令一起使用,例如:kill -9 -进程组ID
options:
0 :表示阻塞状态回收子进程
WNOHANG:表示非阻塞状态回收子进程
status:保存进程退出的状态,可看wait函数参数的用法。
借助宏函数来进一步判断进程终止的具体原因。
宏函数可分为如下三组:
1. WIFEXITED(status) 为非0 → 进程正常结束
WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
2. WIFSIGNALED(status) 为非0 → 进程异常终止
WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
*3. WIFSTOPPED(status) 为非0 → 进程处于暂停状态
WSTOPSIG(status) 如上宏为真,使用此宏 → 取得使进程暂停的那个信号的编号。
WIFCONTINUED(status) 为真 → 进程暂停后已经继续运行
返回值:
成功:返回清理掉的子进程ID;
失败:-1(无子进程)
特殊返回值:
当返回0:参数3为WNOHANG,表示子进程正在运行。
想要了解更多回收子进程的方法,请看这篇文章:
linux_回收子进程(何为孤儿进程、僵尸进程、wait函数、waitpid函数)
4.SIGCHLD信号注意问题
1.子进程继承了父进程的信号屏蔽字和信号处理动作,但子进程没有继承未决信号集spending。
2.注意注册信号捕捉函数的位置,应该在fork之前,阻塞SIGCHLD信号。注册完捕捉函数后解除阻塞。
以上就是本次的分享了,希望能对大家有所帮助。