在学习fork时,了解了子进程与父进程的概念,打算敲代码来实践认识一下。发现了一个很奇怪的问题,使用fork()之后,父进程中pid返回值是子进程,但是子进程中调用getppid(),得到的返回值却不是父进程。
我们先来复习下 fork(),getpid()和getppid()三个函数:
查看manual page:
fork:
pid_t fork(void);
//creates a new process by duplicating the calling process.
// On success, the PID of the child process is returned in the parent, and 0 is returned in the child.
可知道fork用于复制一个和当前进程几乎一样的子进程,父进程返回的PID就是子进程的PID(Process ID),子进程则返回0.
getpid()和getppid:
pid_t getpid(void);
//returns the process ID of the calling process.
pid_t getppid(void);
//returns the process ID of the parent of the calling process.
即可知道,getpid()返回值为调用getpid()进程的PID,而getppid()返回调用这个函数进程的父进程的PID。
那么,为了实际的认识到子进程与父进程的关系,开始写代码了!实际操作下
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
printf("I am a child process!\n");
printf("pid:%d,parent_pid:%d\n",getpid(),getppid());
}
else
{
printf("I am a parent process!\n");
printf("pid:%d,child_pid:%d\n",getpid(),pid);
}
return 0;
}
按照道理来说,父进程中,getpid()打印的是父进程自己的PID,pid打印的是子进程的PID。而子进程中,getpid()打印的是子进程自己的PID,getppid()应该打印的是父进程的PID.
但是运行后,发现结果如下:
父进程中getpid()确实是显示了子进程的PID:4370,但是子进程中调用getppid()返回的竟然不是父进程的PID,而是1852。
这是什么原因呢?我们先来看一下1852是什么:
(用ps命令可以查看进程的PID,或者根据PID查看进程。)
在终端输入:
ps 1852
会发现1852对应的进程是 init --user。
这到底是什么情况呢?init --user到底是什么?
查找资料后发现,有博主提到了“孤儿进程”这一概念Ubuntu中fork创建孤儿进程与收养,我觉得这很有意思。
大致意思就是:当使用fork()创建子进程后,主函数调用时,父函数先于子函数被调用,当父函数完成调用被摧毁后,才调用子函数。也就是说,当子函数被调用时,父函数已经被“杀死”了,这时的子进程便成了“孤儿进程”,init --user即会收养这个子进程。所以,子进程的父进程发生了改变,变为了 init --user。
而getppid返回值为1也是同样的情况,是由于父进程先退出了,造成子进程被init(PID=1)接管,所以用getppid出来的是1。
解决方法:
说了这么多,那么到底解决方法是什么呢?到底如何使getppid的返回值显示正常?或者说如何能不“杀死”父进程便能调用子进程呢?
方法很简单:在父进程调用后加上 sleep()函数即可。也就是让父进程陷入睡眠,而不导致它被摧毁。
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
pid_t pid = fork();
if(pid == 0)
{
printf("I am a child process!\n");
printf("pid:%d,parent_pid:%d\n",getpid(),getppid());
}
else
{
printf("I am a parent process!\n");
printf("pid:%d,child_pid:%d\n",getpid(),pid);
sleep(1);
}
return 0;
}
这时子进程中的getppid()终于显示正常了!完美!