在 while 循环内部的 fork() 内部再次调用了 fork()。

3
请看这里的代码。我的计划是在一个 while 循环内执行一个 for 语句。在 for 循环后,我使用 fork。现在我有一个父进程和一个 child1。在父进程中,我执行另一个 fork,得到一个父进程和 child2。现在我的问题是:
1)为什么当 x=3 时,“fork1 successful”语句会打印两次?
2)对于 x=2,与 x=3 发生了相同的问题。它说 fork1 和 fork2 都成功了,但没有进入 child1 和 child2。它跳过了“n=waitpid(-1, &status, 0);”这一行,直接打印 n,然后减少 x 并转到“x=1;”。
3)对于 x=1,我认为输出混乱了,为什么在 SENDING 1 和 SENDING 2 之间打印了一个“child1 pid=4783”。fork1 又打印了两次。
请帮我解决这些问题。我一直在阅读帖子,但似乎没有看到类似的问题。我可能漏掉了什么?非常感谢!以下是我的代码片段:
while(x>0)
{
    printf("x=%d\n", x);
    for(i=0; i<3; i++)
    {
        printf("SENDING %d\n", i);
    }

    pid1=fork();
    printf("fork1 successful\n");
    if(pid1>0)
    {
        printf("RECEIVING %d\n", i);
        pid2=fork();
        if(pid2>0)
        {
            printf("fork2 successful\n");
            n=waitpid(-1, &status, 0);
            printf("%d\n", n);

            if(n==pid1) //sleep done
            {
                kill(pid2, SIGKILL);
                printf("Child1 ran. Child2 killed.\n\n");
            }

            else if(n==pid2) //scanf received               
            {
                kill(pid1, SIGKILL);
                printf("Child2 ran. Child1 killed.\n\n");
            }
        }    
        else
        {
            printf("child2 pid=%d\n", getpid());            
            scanf("%d", &y);
            exit(1);
        }
    }
    else
    {
        printf("child1 pid=%d\n", getpid());
        sleep(5);
        exit(0);
    }
x--;
}

以下是结果:
x=3

SENDING 0

SENDING 1

SENDING 2

fork1 successful

RECEIVING 3

fork1 successful

child1 pid=4781

fork2 successful

child2 pid=4782

4781

Child1 ran. Child2 killed.

x=2

SENDING 0

SENDING 1

SENDING 2

fork1 successful

RECEIVING 3

fork1 successful

fork2 successful

4782

x=1

SENDING 0

SENDING 1

child1 pid=4783

SENDING 2

fork1 successful

RECEIVING 3

child2 pid=4784

fork2 successful

child2 pid=4786

fork1 successful

child1 pid=4785

1

4784

3
你的问题太多,都混在一起了,让人感到困惑。对于你前两个问题的答案很简单。你把 printf 放在 fork 之后,因此父进程和子进程都会输出该行,并且你看到那行被输出了两次。不清楚你所说的“child1 和 child2 都没有进入”的意思。输出显示它们确实有进入——child1 pid=child2 pid= 的输出来自子进程。 - kaylum
抱歉,我的错误。我想说的是对于 x=2,child1 和 child2 的 pid 没有被打印出来,这就是我所说的 "did not enter both child1 and child2" 的意思。但我注意到对于 x=1,4 个 child pid 被打印了。 - dums
稍微相关的提示:在调用fork之前确保调用fflush,否则如果输出被重定向,程序会突然以奇怪的方式失败。 - o11c
1个回答

1
我认为你假设n = waitpid(-1,& status,0)会暂停,直到其中一个子进程完成。 waitpid 将在任何子进程的任何更改后返回。 如果您将变量“x”添加到打印语句中,并添加一个语句以显示waitpid 的状态返回值,则可以看到在第二个循环中,其中x = 2 waitpid 语句被触发了上一个循环过程的终止信号之一。 事情变得更加混乱 - 因为进程可能会抢占彼此。 在您的原始代码中,可以看到两个child1进程出现在x = 1处。
x=3
[3] SENDING 0
[3] SENDING 1
[3] SENDING 2
[3] fork1 successful
[3] RECEIVING 3
[3] fork2 successful
[3] fork1 successful
[3] child1 pid=8166
[3] child2 pid=8167
[3] child1 exiting
[3] process ID 8166 returned status 0.[3] Child1 ran. Child2 killed.

x=2
[2] SENDING 0
[2] SENDING 1
[2] SENDING 2
[2] fork1 successful
[2] RECEIVING 3
[2] fork1 successful
[2] fork2 successful
[2] process ID 8167 returned status 9.x=1
[1] SENDING 0
[1] SENDING 1
[1] SENDING 2
[2] child1 pid=8171
[2] child2 pid=8172
[1] fork1 successful
[1] RECEIVING 3
[1] fork1 successful
[1] child1 pid=8173
[1] fork2 successful
[1] child2 pid=8174
[2] child1 exiting
[1] child1 exiting
[1] process ID 8171 returned status 0

解决这个问题的一种方法是检查waitpid的状态:

do
{
  n=waitpid(-1, &status, 0);
  printf("[%d] process ID %d returned status %d.", x, n, status);
  if (WIFEXITED(status)==0)
     printf("This is NOT an exit status, so I will keep looping....\n");
  else
     printf("\n");

 } while (WIFEXITED(status)==0);

然后我相信您会得到预期的结果:

x=3
[3] SENDING 0
[3] SENDING 1
[3] SENDING 2
[3] fork1 successful
[3] RECEIVING 3
[3] fork2 successful
[3] fork1 successful
[3] child1 pid=8267
[3] child2 pid=8268
[3] child1 exiting
[3] process ID 8267 returned status 0.
[3] Child1 ran. Child2 killed.

x=2
[2] SENDING 0
[2] SENDING 1
[2] SENDING 2
[2] fork1 successful
[2] RECEIVING 3
[2] fork2 successful
[2] process ID 8268 returned status 9.This is NOT an exit status, so I will keep looping....
[2] fork1 successful
[2] child1 pid=8270
[2] child2 pid=8271
[2] child1 exiting
[2] process ID 8270 returned status 0.
[2] Child1 ran. Child2 killed.

x=1
[1] SENDING 0
[1] SENDING 1
[1] SENDING 2
[1] fork1 successful
[1] RECEIVING 3
[1] fork1 successful
[1] child1 pid=8273
[1] fork2 successful
[1] process ID 8271 returned status 9.This is NOT an exit status, so I will keep looping....
[1] child2 pid=8274
[1] child1 exiting
[1] process ID 8273 returned status 0.
[1] Child1 ran. Child2 killed.

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