【问题标题】:fork() used as for cycle condition generates race condition?用于循环条件的 fork() 会生成竞争条件?
【发布时间】:2012-01-01 20:55:19
【问题描述】:

好的,这是我们今天操作系统考试的练习题

在 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 ? 并且是 2 由父亲打印,1 由第一个孩子打印?

最后一件事:

您将如何重写此 fork-condition-for 以使其更具可读性(例如 if 语句)

【问题讨论】:

    标签: c linux operating-system fork


    【解决方案1】:

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

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

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

    您可以将for() 循环重写为while() 循环,并使&amp;&amp; 的短路评估显式:

    int  main()
    {
        int i;
    
        i = 2;
        while (i >= 1) {
            if (fork() != 0)
                break;
    
            printf("%d\n", i);
            i--;
        }
    
        exit(EXIT_SUCCESS);
    }
    

    【讨论】:

      【解决方案2】:

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

      所以i 发生的情况是,它在子代中的值与在分叉时在父代中的值完全相同。

      所以,当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&gt;=1 并且因为 short-circuit evaluationfork不执行。这个child1.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);
      }
      

      【讨论】:

        猜你喜欢
        • 2010-09-25
        • 2021-08-27
        • 2018-07-24
        • 1970-01-01
        • 2012-11-24
        • 2017-03-24
        • 1970-01-01
        • 2013-05-09
        • 1970-01-01
        相关资源
        最近更新 更多