【问题标题】:Printing using fork使用叉子打印
【发布时间】:2013-03-02 21:51:02
【问题描述】:

我无法理解输出的打印顺序...

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(void)
{
    int index;
    for (index = 1; index < 4; index++)
    {
        printf("HI\n"); 
        fork();
    }
    printf("Unix System Programming\n");
    exit(0);
}

很容易理解,当我只打印 unix 编程系统时,fork 工作了 2^n 次……但是当我用它打印 HI 时……我不明白为什么这个顺序? 输出:

HI
HI
HI
HI
HI
Unix System Programming
HI
HI
Unix System Programming
Unix System Programming
Unix System Programming
Unix System Programming
Unix System Programming
Unix System Programming
Unix System Programming

【问题讨论】:

  • 输出有什么让你困惑的地方?
  • 提示:如果您多次运行它,很可能每次都会看到不同的序列...

标签: c


【解决方案1】:

为了更好的可见性,我刚刚修改了代码

int main(void)   
    {  
        int index;  
        for (index = 1; index < 4; index++)  
        {
            printf("We are in loop with  process id=%d\n",getpid());
            if(!fork()) { //Child process
               printf("Came inside chid with process id=%d\n",getpid());
              // _exit(0);
            } else {     //Parent process
              printf("Came inside parent with process id=%d\n",getpid());
           }
        }
        printf("We are out of loop with  process id=%d\n",getpid());
        exit(0);
    }

    [OP]   
    We are in loop with  process id=2258   -----> Main Parent   
    Came inside parent with process id=2258   
    We are in loop with  process id=2258  
    Came inside child with process id=2259  
    We are in loop with  process id=2259  
    Came inside parent with process id=2258  
    We are in loop with  process id=2258  
    Came inside parent with process id=2259  
    We are in loop with  process id=2259  
    Came inside parent with process id=2258  
    We are out of loop with  process id=2258 ----> "Outer block of loop referring main Parent  Here exit(0) will rip parent process of pid 2258 "      
    Came inside parent with process id=2259     
    We are out of loop with  process id=2259   
    Came inside child with process id=2263   
    We are out of loop with  process id=2263   
    Came inside child with process id=2261   
    We are in loop with  process id=2261   
    Came inside parent with process id=2261   
    We are out of loop with  process id=2261   
    Came inside child with process id=2264   
    We are out of loop with  process id=2264   
    Came inside child with process id=2262   
    Came inside child with process id=2260   
    We are out of loop with  process id=2262   
    We are in loop with  process id=2260   
    Came inside parent with process id=2260   
    We are out of loop with  process id=2260   
    Came inside child with process id=2265   
    We are out of loop with  process id=2265   

首先我们必须考虑将要执行 3 次的循环 每次fork都会产生1个孩子,并且肯定会有一个父母,并且执行将完全 依赖于调度可能是孩子也可能是父母。

一旦你有更多的迭代值,这将变得非常令人头疼。

现在让孩子洗干净

    int main(void)   
            {  
                int index;  
                for (index = 1; index < 4; index++)  
                {
                    printf("We are in loop with  process id=%d\n",getpid());
                    if(!fork()) { //Child process
                       printf("Came inside chid with process id=%d\n",getpid());
                       _exit(0);
                    } else {     //Parent process
                      printf("Came inside parent with process id=%d\n",getpid());
                   }
                }
                printf("We are out of loop with  process id=%d\n",getpid());
                exit(0);
            }

    We are in loop with  process id=2393
Came inside parent with process id=2393
We are in loop with  process id=2393
Came inside chid with process id=2394
Came inside parent with process id=2393
We are in loop with  process id=2393
Came inside parent with process id=2393
We are out of loop with  process id=2393
Came inside chid with process id=2396
Came inside chid with process id=2395

所以上面的OP现在更清楚了三倍父和三倍子执行。

【讨论】:

    【解决方案2】:

    不能保证计算机选择哪个顺序来调度进程,一个进程可以在另一个进程执行单行之前完全执行。

    输出的一种可能解释:

    列是进程,索引在括号中

    “USP”是“Unix 系统编程”
    “FORK”是进程分叉的时间
    “CREATE”是创建进程的时间

    1      2      3      4      5      6      7      8
    HI (1)
    FORK   CREATE
    HI (2)
    FORK          CREATE
           HI (2)
           FORK          CREATE
    HI (3)
    FORK                        CREATE
                         HI (3)
                         FORK          CREATE
    USP
                  HI (3)
                  FORK                        CREATE
           HI (3)
           FORK                                      CREATE
           USP
                  USP
                         USP
                                USP
                                       USP
                                              USP
                                                     USP
    

    以上不太可能是实际输出,因为我们不知道计算机以什么顺序调度进程。您可以在打印语句中添加进程 ID 以指示任何给定输出行属于哪个进程。

    【讨论】:

      【解决方案3】:

      还可以通过查询每个进程的 PID 来更详细地了解正在发生的事情:

      #include <sys/types.h>
      #include <unistd.h>
      #include <stdio.h>
      
      int main(void)
      {
          int index;
          for (index = 1; index < 4; index++)
          {
              printf("HI: pid %d with i=%d will now fork\n", getpid(), index);
              if (0 == fork())
              {
                      printf("I am a new process with i=%d and pid=%d\n", index, getpid());
              }
          }
          printf("Unix System Programming from pid %d\n", getpid());
          exit(0);
      }
      

      至于 printf()s 的顺序,事实是新进程在完全生成之前需要 随机 时间(很小,几乎为零,但仍然是随机的),并且time 与父进程产生更多进程并终止所需的时间处于同一数量级。

      因此,您可能有:

      process 1 prints "HI" and spawns process 2
      process 2 prints "HI" and...
      process 1 prints "HI" and spawns process 3
                                   ... spawns process 4
      ...process 2 terminates ("Unix programming")
      ...process 3 terminates ("Unix programming")
      ...process 4 prints "HI"
      

      下一次可能进程 2 在进程 3 生成之前成功打印 HI,依此类推。如果您需要确定性序列,则必须实现某种类型的进程同步。

      【讨论】:

      • 打印没有警告的 pid,你应该强制转换:(int) getpid()。一个好的做法是检查fork 是否成功,否则检查{ perror("fork"); exit(1); }
      • 是和不是。便携,可能是的;但至少在 Linux 上,pid_t 原来是带符号的 32 位整数类型 (__S32_TYPE),因此可以安全地自动转换;事实上,gcc -ansi -pedantic -W -Wall,一旦包含stdlib.h,编译时完全没有警告。至于fork() 检查,我大体上完全同意-应该检查可能失败的所有函数-但是在这个简单的测试用例中,这将是不必要的复杂化。尽管如此,+1 还是提出了一个很好的观点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-11
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      相关资源
      最近更新 更多