linux中fork中一个子进程,这个子进程需长期运行,而父进程又不想使用wait来等待子进程结束;为了避免产生僵死进程,于是想到了两次fork的方法,让那个进程作为孙进程。但是,如果想在父进程中获得孙进程的pid,该如何做呢?因为子进程知道孙进程的pid,于是想到了使用管道把孙进程的pid由子进程传递给父进程。下面是代码片段。
/**Function:start a tor process.we call fork twice to aviod zombie process
*Parameter:none
*Retval:succeed-pid of the started tor process;failed-'-1'
*/
pid_t start_tor()
{
pid_t pid;
int fd[2];
char line[8];
if(pipe(fd)<0){
perror("pipe failed");
return -1;
}
if((pid=fork())<0){
perror("fork failed");
return -1;
}else if(pid==0){ //first child
close(fd[0]); //close read end
if((pid=fork())<0){
perror("fork failed");
}else if(pid>0){
sprintf(line,"%d/0",pid);
write(fd[1],line,sizeof(line)); //write tor pid to pipe
exit(0);
}
//we are the second child;our parent becomes init as soon as our real parent calls exit() in that statement above.
//change work directory
char *home_dir;
if((home_dir=getenv("HOME"))==NULL){
perror("get $HOME failed");
exit(1);
}
char work_dir[64];
sprintf(work_dir,"%s/tor/tor/bin/",home_dir);
if(chdir(work_dir)==-1){
perror("chdir failed");
exit(1);
}
//redirect tor stdout to log file
int filedes;
umask(0);
if((filedes=open("tor_log",O_RDWR|O_CREAT|O_TRUNC,RWRWRW))<0){
perror("open tor_log failed");
exit(1);
}
if(dup2(filedes,1)<0){
perror("dup2 failed");
exit(1);
}
if(execlp("/home/hyh/tor/tor/bin/tor","tor",(char *)0)==-1){
perror("execlp failed");
exit(1);
}
if(DEBUG){
printf("exit from tor,you should not see this tip/n");
}
exit(1);
}
close(fd[1]); //close write end
read(fd[0],line,8); //read tor pid from pipe
if(waitpid(pid,NULL,0)!=pid){
perror("waitpid failed");
return -1;
}
if(DEBUG){
sleep(60);
}
return atoi(line);
}
APUE 2 Edtion 对管道的介绍如下:
管道是UNIX系统IPC的最古老形式,并且所有UNIX系统都提供此种通信机制。管道有以下两方面局限性:
(1)它们是半双工的,即数据只能在一个方向上流动。现在,某些系统提供全双工管道,但是为了最佳的可移植性,我们决不应预先假定系统提供此特性。
(2)它们只能在具有公共祖先的进程之间使用。通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
另外UNIX中父子进程之所以可以通过管道进程通信,我猜是由于fork的子进程继承了父进程的文件描述符表的缘故。
参考:APUE 2 Edition 183 Page
APUE 2 Edition 398 Page