如何在父进程终止后终止所有子进程?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在父进程终止后终止所有子进程?相关的知识,希望对你有一定的参考价值。

我可以通过父进程杀死子进程。但是如果父进程有多个子进程会发生什么?

例如,在下面的代码中,有一个父进程和6个子进程。如何在父进程终止后立即终止其他六个子进程?

如果您运行此代码,则父项将在5秒后终止。此子进程在另外5秒(总共10秒)后终止。

但我希望在父进程终止后立即终止6个子进程。所以父进程和6子进程应该在5秒后终止。

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

int main() 
{ 
    for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.) 
    { 
        if(fork() == 0) 
        { 
            printf("Started [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            sleep(10); //child waits 10 seconds,then it exitted.

            printf("Exitted [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            exit(0); 
        } 
    } 

    //parent
    sleep(5);  //parent will wait 5 seconds than it will exit
    printf("Parent terminated
");
    exit(0); //parent terminated.(how can I exit the the other 6 child processes too?)

} 
答案

这是一个可能更便携的解决方案。

fork(2)系统调用将返回子进程的PID,您可以存储PID,然后您可以使用kill(2)向子进程发送信号并终止它们。

请注意,SIGKILLSIGTERM信号可能需要父进程的某些特权。如果它没有这样的权限,您可以将SIGCONT发送到子进程,并修改子进程中的SIGCONT信号处理程序。

!警告牌

从使用exit()的信号处理程序是不安全的。我刚检查了手册man 7 signal,发现它不是异步安全的。你可以使用_exit_Exitabort

一些伪代码:

#include <stdio.h> 
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void* handler(int sig){
    _exit(0);
}
int main() 
{ 
    pid_t children[6];
    for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.) 
    { 
        if((children[i] = fork()) == 0) 
        { 
            signal(SIGCONT,handler);
            printf("Started [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            sleep(10); //child waits 10 seconds,then it exitted.

            printf("Exitted [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            exit(0); 
        } 
    } 

    //parent
    sleep(5);  //parent will wait 5 seconds than it will exit
    for(int i=0;i<6;i++)
        kill(children[I],SIGCONT);
    printf("Parent terminated
");
    exit(0); //parent terminated.(how can I exit the the other 6 child processes too?)

}
另一答案

在Linux上,您可以使用prctl通过信号请求通知您父母的死亡(跳过错误检查)。

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

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

int main() 
{ 
    for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.) 
    { 
        if(fork() == 0) 
        { 
            prctl(PR_SET_PDEATHSIG, SIGTERM); //<<<<<<

            printf("Started [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            sleep(2);

            printf("Exitted [son] pid %d from [parent] pid %d
",getpid(),getppid()); 

            exit(0); 
        } 
    } 

    //parent
    sleep(1);
    printf("Parent terminated
");
    exit(0);
   //<<< Linux auto-sends the deathsignal to all children

} 

对于POSIX兼容的解决方案,它不需要父进程在其子进程终止时显式终止其子进程,您可以使用async-IO管道。

Async-IO依赖于在filedescriptor事件上发送的信号。在这种情况下,只要确保autoclose关闭管道结束文件的最后一个引用(跳过错误检查),就可以通知内核自动关闭一个死亡进程的文件描述符而导致的close事件:

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>

#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main()
{

    int pipes[6][2];
    for(int i=0;i<6;i++) // loop will run 6 times(there are 6 child processes.)
    {
        pipe(pipes[i]); //create a pipe

        if(fork() == 0)
        {
            //get notified on an event on the read-end (we're aiming for the EOF event)
            fcntl(pipes[i][0],F_SETOWN,getpid()); 
            ioctl(pipes[i][0], FIOASYNC, &(int){1});

            for(int j=0; j<=i; j++) close(pipes[j][1]); //close all write-end ends so the refcount is 1 and the parent has the last ref

            printf("Started [son] pid %d from [parent] pid %d
",getpid(),getppid());

            sleep(2);

            printf("Exitted [son] pid %d from [parent] pid %d
",getpid(),getppid());

            exit(0);
        }
    }

    //parent
    sleep(1);
    printf("Parent terminated
");
    exit(0); 
    //<<<this closes all the last write ends of the pipes and so the children will get notified with a signal 
    //the signal is SIGIO by default, whose default disposition is to kill the process (this can be changed by fcntl(fd,F_SETSIG,TheSignal))



}

以上是关于如何在父进程终止后终止所有子进程?的主要内容,如果未能解决你的问题,请参考以下文章

如何在父进程被终止的情况下保持子进程的活力

在父进程恢复执行之前等待所有子进程 UNIX

如何检查子进程是不是正确终止? [复制]

linux下system函数调用shell命令后,怎样让主进程等子进程返回后,接着执行

在 C 中等待子进程终止的最佳实践

linux处理僵尸进程