我想写这样一个函数,它可以从其他地方调用。使用fork生成子进程并等待主进程返回其主函数。我尝试了这个方法,也尝试了设置一面旗帜来告诉孩子父母回来了。但他们都不正确,我知道原因。我只是想知道我该如何证明这一点?谢谢!
void otherplacecall(){
fpid=fork();
if (fpid == 0) {
printf("i am the child process, my process id is %dn",getpid());
while(getppid()!=1){printf("waitingn");sleep(1);}
if(getppid()==1){
printf("father die!n");
printf("I am dyingn");
exit(0);
}
}
else {
printf("in the parents!, my process id is%dn",getpid());
printf("my son take care of yourselfn");
return 1;
}
}
假设父进程没有终止,则必须手动向子进程发送信号。
设置方法如下:
int run = 1;
void OnSigUsr1()
{
run = 0;
}
///....
signal(SIGUSR1, OnSigUsr1);
pid = fork();
if(pid == 0)
{ //we are the child
//loop until SIGUSR1 comes in
while(run == 1) p_sleep(1000);
}
else
{ //we are the parent
//send the SIGUSR1 signal to child
kill(pid,SIGUSR1);
}
当进程现在得到信号SIGUSR1
时,函数OnSigUsr1
被调用。在这里,你可以设置一些全局变量为false。
kill
命令不会杀死孩子,但会向它发送一个信号(这个名字可能会误导人)。
当你的父进程终止时,虽然你不需要手动发送信号,但可以告诉Linux在父进程死亡时给你发送信号。
可以通过添加
来实现prctl(PR_SET_PDEATHSIG, SIGUSR1);
现在你的子进程得到了父进程"死亡"的信号。
如果你不需要任何额外的处理,但只是子终止你可以"跳过"自定义信号处理和发送SIGTERM
而不是SIGUSR1
。默认情况下,这将结束进程。
你应该阅读一些关于信号的内容,这将有助于你更好地理解代码。
你说你想让孩子
等待主进程返回其主函数
。这有点难以理解,但我认为您的意思是希望子进程等待,直到它的父进程返回到执行fork()
的函数的调用者。目前尚不清楚调用者是否被期望为该进程的main()
函数,但这实际上没有任何区别。
然而,没有函数可以直接控制它返回时发生的事情。它能做的最好的事情就是在返回之前立即执行一些操作。
此外,由于您提供的函数不是main()
,因此没有理由假设父进程在从该函数返回时终止。在进程终止之前,子进程仍然是它的子进程,因此不会被进程1继承。
由于程序实际上没有像您期望的那样工作,我认为父进程确实没有终止,因此您需要一种不同的方法。具体来说,您需要某种形式的进程间通信(IPC)。有几种口味可供选择,作为奖励,其中许多不需要孩子忙着等待。比较可能的选项包括
- 进程共享互斥锁或信号量
- 管道
其中,我推荐最后一个。它可以像这样:
void otherplacecall(){
int pfd[2];
pid_t pid;
char c;
if (pipe(pfd)) {
// ... handle error in pipe() ...
return;
}
switch(pid = fork()) {
case -1:
// (parent) ... handle error in fork() ...
break;
case 0:
// child
printf("child: my process id is %dn", (int) pid);
if (close(pfd[1])) {
// ... handle error in close() ...
_Exit(1);
}
if (read(pfd[0], &c, 1) < 0) {
// ... handle error in read() ...
}
puts("child: received the signal to proceed");
puts("child: I terminating");
_Exit(0);
default:
// parent
close(pfd[0]);
puts("parent: my son, take care of yourself");
close(pfd[1]); // this will cause the child's read() to return
}
}
这种方法的特点之一是,如果父确实终止,那么它的管道末端副本将被关闭,即使它没有显式关闭它们,所以子进程将继续。在其他情况下不会发生这种情况,例如子进程正在等待信号,而父进程在发送信号之前死亡。