以下程序中的控制流程是什么?

时间:2015-09-17 17:47:37

标签: c pipe fork


我正在学习使用叉子和管道。我写了下面的代码.child1写了#34;孩子1"和child2写" child 2",父母读取值。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
int pfds[2];
char buf[30];
pipe(pfds);
if(fork() == 0)     //child 1
{
    close(pfds[0]);
    write(pfds[1],"child 1",sizeof(buf));
}
else
{   
    if(fork() == 0)  //child2
    { close(pfds[0]);
      write(pfds[1],"child 2",sizeof(buf));

    }
    else
    {
      close(pfds[1]);
      read(pfds[0],buf,sizeof(buf));
      printf(" read: %s ",buf);
      wait(NULL);

    }

close(pfds[1]);
read(pfds[0],buf,sizeof(buf));
printf(" read: %s ",buf);       
wait(NULL); 
}


}


我的输出是:read:some_garbage_value read:child 1 read:child 2
为什么我读了3次?我只想要它2次(child1和child2)。如何执行语句?
P.S:抱歉,如果这是一个菜鸟问题。我刚刚开始学习fork(),exec()和管道。

2 个答案:

答案 0 :(得分:1)

忽略代码中过多的错误和缺少检查(已经在注释中指出),您要求的问题是由fork()将流分成两个在两个执行的路径的事实给出的不同的过程。这意味着在fork()之后,您将有两个并行执行,其中一个fork()返回0而另一个返回创建进程的pid。

因此,在第一个fork()之后,您将有一个执行if分支的进程和一个执行else分支的进程。

然后你再次以这种方式完成一段代码:

if (fork() == 0) {
  code1;
}
else {
  code2;
}

code3;

现在想象一下fork()返回不同值的两个不同进程,你有:

if (0 == 0)
  code1;
else
  code2;

code3;

if (123 == 0)
  code1;
else
  code2;

code3;

这意味着两条路径被解析为:

code1;
code3;

code2;
code3;

这解释了为什么您创建的第二个孩子尝试阅读。

答案 1 :(得分:1)

以下是发生的事情:

First fork:

  • 第一个孩子:只是写作和退出
  • 父母一次性分叉
    • 孩子关闭pfds[0],写道......然后在其他人之后继续阅读刚刚关闭的pfds[0]。由于您没有测试read的返回值,第二个子项会将随机缓冲区打印到stdout
    • parent从pfds[0]读取缓冲区并将其打印到stdout,然后在if之后继续读取第二个缓冲区并将其打印到stdout

所以我们有一个垃圾输出和两个正确的输出。编译器是对的。

您可以通过立即从孩子2返回来轻松修复它:

if(fork() == 0)  //child2
{ close(pfds[0]);
  write(pfds[1],"child 2",sizeof(buf));
  return 0;   /* stop child2 immediately */
}
else