子进程的父进程ID与父进程的PID不同

4

我正在尝试使用C语言中的fork()函数在Linux系统中处理多个进程,以下是我的代码:

p1 = fork();

if(p1 != 0){
    p2 = fork();
}

printf("My PID is %d\n",getpid());
printf("My parent PID is %d\n",getppid());

现在假设父进程的ID是100,两个子进程(p1、p2)的ID分别为101和102,init进程的PID将为0,我的期望输出是:

My PID is 100
My parent PID is 0

My PID is 101
My parent PID is 100

My PID is 102
My parent PID is 100

相反,我看到了不同的东西,两个子进程具有相同的 PPID,但第一个进程的 PID 与其不同。以下是我得到的示例输出:

My PID is 3383
My parent PID is 3381

My PID is 3387
My parent PID is 1508

My PID is 3386
My parent PID is 1508

我的问题是,这两个子进程的父 PID 不应该是 3383 吗?希望有人能解释一下这里的所有工作原理以及我在做什么(或者想错了什么)。

3
在两个printf完成后添加一个sleep会发生什么? - Mohit Jain
@MohitJain 这实际上修复了它,这是为什么呢?我的意思是,在printf之后睡眠应该不会改变任何东西,因为进程将被创建并且fork一样... - argamanza
2个回答

7

[从评论中确认]

你的输出与时间有关。如果父进程在子进程之后结束,那么你的输出将如预期一样。

如果父进程在子进程之前结束,输出可能会出现意外情况(在父进程不存在之前,父进程的id会不同)。一旦父进程终止(结束),init或其他实现定义进程(在您的情况下为1508)将成为孩子(们)的新父进程。这些孩子被称为孤儿进程。

根据《单一UNIX规范版本2》的退出手册:

调用进程的所有现有子进程和僵尸进程的父进程ID应设置为实现定义的系统进程的进程ID。也就是说,这些进程应该由一个特殊的系统进程继承。

为了避免这种情况,确保在获取父进程PID时父进程仍然存活。一种方法是在父进程(或所有进程)退出之前添加等待。


1
有道理,但对于“init”来说,“1508”仍然是一个奇怪的PID。 - alk
@alk 这并不是必须的初始化。init 的 pid 是 1。实际上,孤儿进程的 ppid 被设置为实现定义的进程 id。 - Mohit Jain
implementation-defined” 是指什么,操作系统吗?这里是 Linux。我似乎漏掉了什么。 - alk
我确认输出是由于父进程过早退出导致的。为了进行快速测试,我在退出之前添加了一个 sleep(1); 调用,然后 PID 就如最初预期一样。 - Tom Karzes
@alk 是的,内核规格。 - Mohit Jain
显示剩余2条评论

1

你的代码没有问题

只是因为父进程在子进程完成之前退出,所以它们变成了孤儿,并被init或者任何实现定义的进程(在你的情况下是1508)接管。

尝试使用wait();等待父进程执行完所有子进程的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接