【问题标题】:Flow of the fork, how many forks do I have?叉子的流程,我有多少个叉子?
【发布时间】:2016-10-23 21:11:05
【问题描述】:

我已经执行了这段代码。 我知道消息的顺序是任意的(因为我明确没有使用信号量) 我的程序流程看起来如何,为什么?

父级被执行,所以“baz”被打印一次。有人可以解释为什么不打印“bar”吗?为什么我得到“foo”(if 语句为真)两次而不是一到三次(不是我想要这个但我想了解逻辑)(因为一位同事说我应该得到三倍 foo它)?

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
  int p;
  p = fork();
  if (fork()==0) {
    if (execl("/bin/echo", "/bin/echo", "foo", 0) == -1) {
      fork();
    }
  printf("bar\n");
  }
  else {
    if (p!=0) execl("/bin/echo", "/bin/echo", "baz", 0);
  }
}

【问题讨论】:

  • 只是对未来问题的提示。为了避免投票(我不是其中之一),如果问题是“如果我只是阅读man page,我可能会弄清楚......”,你可能应该先尝试一下。这里的人很乐意帮助您解决编程问题,但不是来解释如何阅读基本文档。虽然这个问题确实显示了努力,但它可能属于基本信息方面。
  • 你可以从字面上观察这个程序做了什么,要么使用strace -f,要么插入调试打印(包括getpid()的值,这样你就知道它是哪个进程)。

标签: c fork ipc


【解决方案1】:

execl 不返回,它将整个过程映像替换为 /bin/echo。 因此有零个“条”。

    if (execl("/bin/echo", "/bin/echo", "foo", 0) == -1) {
      fork();
    }
    /* Not reached if execl succeeded.
    Because the exec family of functions replace the process image with
    another executable.  Flow will never return, unless there is an
    error. */
    printf("bar\n");

有两个“foo”。

  int p;
  p = fork();
  /* Two processes now */
  if (fork()==0) {
      /* Two child processes here. */
      execl("/bin/echo", "/bin/echo", "foo", 0); /* (Simplification) */
      /* Two (/bin/echo foo) here, flow will never return back */
  }

只有一个“baz”。

int p;
p = fork();
/* if block removed for simplicity */
if (p != 0)
{
    /* Only the initial parent process. */
    execl("/bin/echo", "/bin/echo", "baz", 0);
}

【讨论】:

  • foo 的数量呢?
  • 我应该在程序中得到两到三倍的 foo 吗?
  • p = fork(); 产生一个新进程(总共 2 个)。其中每一个都运行if (fork() == 0),它会产生另外两个进程。原来的 2 没有进入 if 语句,因为 fork 在其中返回了一个非零值。因此只有 2 个最新进程运行 execl
  • 所以你的意思是我的同事错了?而且我应该有两次 foo 和一次 baz。
  • @TanjaMeeren “应该”是什么意思?您已经在原始问题中向我们提供了事实:baz 打印一次,bar 根本不打印,foo 打印两次。你已经知道你的同事错了。
【解决方案2】:

首先您需要了解exec 系列系统调用将整个程序替换为其他程序。在您的情况下,“回声”程序。除了execl 调用之外的任何内容都不会执行。

这是正在发生的事情:

  1. 您的父进程(称为 p0)执行 p=fork(),它派生出一个克隆进程 p1
  2. p0 再次执行 if (fork()==0) 派生另一个克隆进程 p2
  3. p0 然后执行打印“baz”的 else 语句的主体。

  4. 在被分叉后,p1 执行if (fork()==0) 语句,该语句分叉另一个进程 p3。与 p0 一样,p1 将进入 else 语句但不会打印“baz”,因为在 p0 分叉时设置了 p p1 实际上等于 0(因为 p1 是 p0 的孩子)。

  5. p2 进入 if 语句体并执行 execl 函数,将当前程序替换为打印“foo”的 echo 程序。

  6. 与 p2 一样,p3 进入 if 语句体并执行 execl 函数,该函数将当前程序替换为打印“foo”的 echo 程序"。

【讨论】:

    【解决方案3】:

    第一个fork 创建两个进程, 然后两者都进行第二次分叉。

    p0    (p=$pid)              //first fork
                    p1  (p==0)  
    
       p01                p11      //second fork
          exec              exec
    

    在叶子子节点(p01p11)中,第二个 fork 后面跟着一个 exec,如果成功,则结束旧的进程映像。这应该在stdout 上给你两个foos。

    父母(p0p1)然后执行以下操作:

    if (p!=0) execl("/bin/echo", "/bin/echo", "baz", 0);
    

    p!=0 测试可能只在p0(原始过程)中成功。 这应该会在stdout 上为您提供一个baz


    (在实际代码中,您还应该检查fork 错误)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-22
      • 2023-04-04
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 2018-12-17
      • 1970-01-01
      • 2021-09-02
      相关资源
      最近更新 更多