用于循环条件的fork()会产生竞争条件吗?

时间:2011-11-19 10:50:20

标签: c linux operating-system fork

好的,所以这是我们今天的操作系统考试的一个例外

在C

中给出了这个程序
#include <unistd.h>
#include <stdlib.h>

int  main(){
    int i;
    for(i=2;i>=1&&!fork();i--)
            printf("%d\n",i);

exit(EXIT_SUCCESS);
}

执行它会给出这个输出:

2
1

我发现模糊不清的是程序如何管理索引“i” 什么是流程执行的正确顺序 (如果有订单或者是调度程序建立的随机订单?)

为什么只有2和1印刷 - 我的假设是:

(father executes the "for" only for i=2, prints 2 then exits ?)
(the first child starts from i=1 forks a child prints 1 exits ?)

此时我的问题是:

是否有第二个孩子分叉但没有进入for? 由父亲打印,第一个孩子打印1个?

最后一件事:

如何重写这个fork-conditioned-for以使其更具可读性(例如if语句)

2 个答案:

答案 0 :(得分:2)

for()循环在循环的每次迭代之前检查条件,包括第一个循环。这意味着原始父进程从i = 2开始并评估i >= 1 && !fork()fork()向父项返回非零PID,向子项返回零,因此父项中的!fork()为false,并且不执行循环:父项退出。

在第一个孩子中,!fork()为真,因此循环执行。它打印2,然后递减i。它现在执行i >= 1 && !fork() - 再次,!fork()在第一个子节点中为false,因此它退出for循环和程序。

在第二个孩子(第一个孩子的孩子)中,!fork()返回true,因此循环执行。它打印1,然后递减i。它现在评估i >= 1 && !fork()。由于i >= 1评估为false,因此永远不会调用fork();它退出循环和程序。此时所有流程都已退出。

您可以将for()循环重写为while()循环,并对&&进行明确的短路评估:

int  main()
{
    int i;

    i = 2;
    while (i >= 1) {
        if (fork() != 0)
            break;

        printf("%d\n", i);
        i--;
    }

    exit(EXIT_SUCCESS);
}

答案 1 :(得分:2)

当你fork时,就像所有程序都被复制粘贴一样,两个相同的过程从那一点开始(尽管父亲得到了孩子的PId作为fork的返回值和孩子得到零)

那么i会发生什么,它会在子节点中具有与fork中父节点相同的值。

所以,当i为2时:

for parent: i>=1 && !fork()  <-- fails
for child1: i>=1 && !fork()  <-- succeeds

所以,2由原始程序的孩子打印。

现在父级已退出且child1正在运行。它执行i--,现在i为1:

for child1:   i>=1 && !fork()  <-- fails
for child1.1: i>=1 && !fork()  <-- succeeds

再次,child1退出,其子,child1.1进入for并打印1.然后执行i--i变为0,i>=1失败,因为{ {3}},fork未执行。这个孩子1.1也退出了。

要回答您的上一个问题,通常会写fork的方式:

pid_t pid = fork();
if (pid)
{
    // in parent
}
else
{
    // in child
}

现在您只需要一个for循环:

#include <unistd.h>
#include <stdlib.h>

int  main(){
    int i;
    for(i=2;i>=1;i--)
        if (fork())
            break;              /* parent wants to break */
        else
            printf("%d\n",i);   /* child prints something */

    exit(EXIT_SUCCESS);
}