叉子的流程,我有多少个叉子?
Posted
技术标签:
【中文标题】叉子的流程,我有多少个叉子?【英文标题】: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()
的值,这样你就知道它是哪个进程)。
【参考方案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
调用之外的任何内容都不会执行。
这是正在发生的事情:
-
您的父进程(称为 p0)执行
p=fork()
,它派生出一个克隆进程 p1。
p0 再次执行 if (fork()==0) 派生另一个克隆进程 p2。
p0 然后执行打印“baz”的 else 语句的主体。
在被分叉后,p1 执行if (fork()==0)
语句,该语句分叉另一个进程 p3。与 p0 一样,p1 将进入 else 语句但不会打印“baz”,因为在 p0 分叉时设置了 p
p1 实际上等于 0(因为 p1 是 p0 的孩子)。
p2 进入 if 语句体并执行 execl 函数,将当前程序替换为打印“foo”的 echo 程序。
与 p2 一样,p3 进入 if 语句体并执行 execl 函数,该函数将当前程序替换为打印“foo”的 echo 程序"。
【讨论】:
【参考方案3】:第一个fork
创建两个进程,
然后两者都进行第二次分叉。
p0 (p=$pid) //first fork
p1 (p==0)
p01 p11 //second fork
exec exec
在叶子子节点(p01
和 p11
)中,第二个 fork
后面跟着一个 exec
,如果成功,则结束旧的进程映像。这应该在stdout
上给你两个foo
s。
父母(p0
和 p1
)然后执行以下操作:
if (p!=0) execl("/bin/echo", "/bin/echo", "baz", 0);
p!=0
测试可能只在p0
(原始过程)中成功。
这应该会在stdout
上为您提供一个baz
。
(在实际代码中,您还应该检查fork
错误)。
【讨论】:
以上是关于叉子的流程,我有多少个叉子?的主要内容,如果未能解决你的问题,请参考以下文章