【问题标题】:pipe example between multiple child-process in CC中多个子进程之间的管道示例
【发布时间】:2017-03-30 16:17:22
【问题描述】:

当我在 C 中处理 pipe() 函数时,我有点困惑。我的目标是在子进程之间传输数据。我希望每个孩子都接受来自fd[0] 的意见并写信给fd[1]。我的代码在这里,但我无法获得任何结果。错误在哪里?我怎么能想象管道?

    int main()
    {

    char *arr = malloc(sizeof(int));
    int num;
    int fd[2];
    char *piping = malloc(10*sizeof(char));
    char *word = malloc(10*sizeof(char));

    while(1)
    {
        printf("enter the number of child: ");
        fflush(stdout);
        fgets(arr, 10, stdin);

        printf("enter word: ");
        fflush(stdout);
        fgets(word, 10, stdin);

        num = atoi(arr);

        pipe(fd);
        for(int i = 0; i < num; i++)
        {
                if(!fork())
                {
                        read(0, piping, 10);
                        if(i != 0)
                        {   
                            dup2(fd[0],0);
                        }
                        if(i != num-1)
                        {
                            dup2(fd[1],1);
                        }
                        write(1, piping, 10);
                }
                else
                    wait(0);
        }
    }   
    return 0;
   }

【问题讨论】:

  • 为什么要动态分配?我看不出有什么需要,在你不需要的地方,你应该避免它。
  • 另外,考虑使用scanf()sscanf() 从用户输入中读取数字。
  • @JohnBollinger 也许你是对的,但这并不重要。这只是一个例子,我试图了解它是如何工作的以及如何实现它。所以,我只是写了任何数字。
  • 此外,dup2() 呼叫对您的作用很小。他们让我对你实际想要达到的目标有点怀疑(如果我猜对了,那么你的做法是错误的),但你的代码实际上做了什么——以及你说它应该做什么-- 无需复制任何文件描述符即可。

标签: c pipe fork stdin file-descriptor


【解决方案1】:

这有很多错误。现在忘记所有管道的东西,看看分叉。代码如下所示:

for(int i = 0; i < num; i++)
{
    if (!fork())
    {
        // in child do something
    }
    else
        wait(0);
}

父级进入循环,创建第一个子级并等待它。

第一个孩子进入循环的第二次迭代,创建一个孩子并等待它

第一个孩子的孩子进入循环的第三次迭代,创建一个孩子并等待它。

以此类推,直到我们有一个由 num - 1 个父母和孩子组成的祖先链。第 num - 1 个子节点简单地退出,这意味着它的父节点将停止等待并继续循环的下一次迭代。它也将退出,因此第 num-2 个子节点将停止等待,但它仍有循环的迭代要进行,因此它会创建另一个子节点并等待它。

您创建的子代可能比您想要的要多得多,因为您忘记了父代和子代在分叉之后都继续执行相同的代码。您可能希望 if ... else 的 if 部分包含 exit(0); 作为其最后一条语句。

但是,您的问题不在那里。在 if 部分,您首先尝试从 stdin 读取,这意味着您所有的许多子进程都将阻塞等待来自终端的输入。

dup 的东西目前毫无意义。除了在您读取标准输入之前您不会将管道的读取端复制到标准输入这一事实之外,当您分叉时,您仍然可以访问管道,除非您调用exec,所以为什么不直接使用它。写的孩子可以直接写到fd[1],读的孩子可以直接读到fd[0]

【讨论】:

    【解决方案2】:

    直接的问题是每个子进程在继续之前都等待从其标准输入(而不是管道)中读取某些内容,并且您没有提供任何输入(或者至少对于所有子进程来说都不够)。也许你打算在read()之前执行dup2()

    虽然修复该问题可能会让您的程序运行完成,但总体策略至少在以下方面存在缺陷:

    • 在开始下一个孩子之前,每个孩子的父母wait()s。这会产生两种问题

      • 您没有任何实际的并发性。那么,分叉的意义何在?
      • 如果孩子们将更多的输出写入管道,那么他们将面临填充其缓冲区并因此阻塞的风险。这会产生死锁,因为缓冲区只会被下一个孩子耗尽,直到其前任终止时才会启动。
    • 每对进程都使用相同的管道进行通信。这仅适用于父级序列化子级的执行(如上所述)。由于此类序列化存在固有问题,除其他原因外,您通常希望每个管道专门用于一对进程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      相关资源
      最近更新 更多