我可以通过父进程杀死子进程。但是如果父进程有多个子进程会发生什么?
例如,在下面的代码中,有一个父进程和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\n",getpid(),getppid());
sleep(10); //child waits 10 seconds,then it exitted.
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(5); //parent will wait 5 seconds than it will exit
printf("Parent terminated\n");
exit(0); //parent terminated.(how can I exit the the other 6 child processes too?)
}
这是一个可能更便携的解决方案。
fork(2)
系统调用将返回子进程的PID,您可以存储PID,然后您可以使用kill(2)
向子进程发送信号并终止它们。
请注意,SIGKILL
和SIGTERM
信号可能需要父进程的某些特权。如果它没有这样的权限,您可以将SIGCONT
发送到子进程,并修改子进程中的SIGCONT
信号处理程序。
!警告牌
从使用exit()
的信号处理程序是不安全的。我刚检查了手册man 7 signal
,发现它不是异步安全的。你可以使用_exit
,_Exit
或abort
一些伪代码:
#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\n",getpid(),getppid());
sleep(10); //child waits 10 seconds,then it exitted.
printf("Exitted [son] pid %d from [parent] pid %d\n",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\n");
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\n",getpid(),getppid());
sleep(2);
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(1);
printf("Parent terminated\n");
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\n",getpid(),getppid());
sleep(2);
printf("Exitted [son] pid %d from [parent] pid %d\n",getpid(),getppid());
exit(0);
}
}
//parent
sleep(1);
printf("Parent terminated\n");
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))
}