【问题标题】:even odd program using fork使用 fork 的偶数程序
【发布时间】:2020-06-16 14:00:34
【问题描述】:

我用fork写了一个偶数和奇数的程序,它有时打印偶数,有时打印奇数。请解释这个问题?

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
        int i;
        if(fork() == 0)
        {
                for(i=1;i<50;i++)
                        if(i%2 == 0)
                                printf("even %d\n",i);
        }
        else
        {
                for(i=1;i<50;i++)
                        if(i%2 != 0)
                                printf("odd %d\n",i);
        }
}

我得到如下输出: 奇数 1 奇数 3 奇数 5 奇数 7 奇数 9 奇数 11 奇数 13 奇数 15 奇数 17 奇数 19 奇数 21 奇数 23 奇数 25 甚至 2 奇数 27 甚至 4 奇数 29 甚至 6 奇数 31 甚至 8 奇数 33 甚至 10 奇数 35 甚至 12 奇数 37 甚至 14 奇数 39 甚至 16 奇数 41 甚至 18 奇数 43 甚至 20 奇数 45 甚至 22 奇数 47 甚至 24 奇数 49 甚至 26 甚至 28 甚至 30 甚至 32 甚至 34 甚至 36 甚至 38 甚至40 甚至 42 甚至 44 甚至 46 甚至 48

【问题讨论】:

  • 你想要的输出是什么?
  • 子打印一个东西,父打印另一个。你到底有什么不明白的?
  • 据我所知,偶数组(最多 50 个)打印,奇数组后最多打印 50 个。@Andrea Pollini

标签: c linux fork


【解决方案1】:

fork()之后会创建一个子进程。

child得到返回值0,打印偶数,parent得到child的进程id,返回值为fork(),打印奇数。

        int i;
        if(fork() == 0)
        {
                for(i=1;i<50;i++)
                        if(i%2 == 0)
                                printf("even %d\n",i);
        }
        else
        {
                for(i=1;i<50;i++)
                        if(i%2 != 0)
                                printf("odd %d\n",i);
        }

但是,父子进程是两个进程,很难确定哪个先运行。 它们可能使用不同的 CPU 内核,因此并行运行,或者只在同一个内核上运行。

实际上,当多个进程在同一个 CPU 内核上运行时,就有了 CPU 调度。 请注意,一个 CPU 核心不能同时做两件事。

CPU调度是确定在某个时间点运行哪个进程的方法。而且通常一个进程在中断之前只有很短的时间运行,然后一直保持到下一次获得资源。

计划工作的进程切换非常快(上下文切换),因此作为人类,当另一个进程正在运行时,您感觉不到该进程保持不变。就像每个进程同时运行一样。

回到你的问题,在odd 49之前打印出一些偶数。比如有odd 25 even 2,表示父进程(想打印奇数)在打印出odd 25后被中断。然后子进程拿到资源,然后打印出even 2

每次奇数后跟偶数是由于父母在那里被打断。另一方面,当奇数在偶数之后打印时,那是因为那里的子进程被中断了。

【讨论】:

    【解决方案2】:

    fork() 成功后,父进程和子进程将基本同时执行。 (正如另一个答案指出的那样,这是通过两者之间的快速上下文切换来实现的。)这些进程的输出可以随时到达输出流。

    附加到问题的评论表明,期望子进程在父进程开始执行其自己的for 循环之前完成其for 循环。为此,必须执行显式的waitwaitpid 调用。这将导致父进程阻塞,直到子进程退出。

    下面修改后的代码显示了包含waitpid 调用。另请参阅下面的输出,其中包含奇数之前的所有偶数。

    其他注意事项:

    • printf 输出受 stdio 缓冲的影响,但这里没有必要显式调用fflush 以确保偶数在奇数之前被完全写入,因为这将完成在孩子退出之前自动进行。

    • 通过调用waitpid,父级还通过作为第二个参数传递的int * 指针收集子级的退出状态。在问题的代码中,永远不会调用 waitwaitpid。因此,如果子进程恰好在父进程之前退出,那么它的退出状态将保存在进程表中(作为“僵尸”进程),直到父进程退出。在此示例中,父进程和子进程将大约同时完成,但一般来说,确保派生子进程的父进程执行后续等待调用(或 signal(SIGCHLD, SIG_IGN); 向内核,不需要孩子的退出状态)。

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
      int i, status;
      pid_t pid;
    
      pid = fork();
      if (pid == 0)
        {
          for(i=1;i<50;i++)
            if(i%2 == 0)
              printf("even %d\n",i);
        }
      else
        {
          if (pid > 0)
            pid = waitpid(pid, &status, 0);
          for(i=1;i<50;i++)
            if(i%2 != 0)
              printf("odd %d\n",i);
        }
      return 0;
    }
    

    输出:

    even 2
    even 4
    even 6
    even 8
    even 10
    even 12
    even 14
    even 16
    even 18
    even 20
    even 22
    even 24
    even 26
    even 28
    even 30
    even 32
    even 34
    even 36
    even 38
    even 40
    even 42
    even 44
    even 46
    even 48
    odd 1
    odd 3
    odd 5
    odd 7
    odd 9
    odd 11
    odd 13
    odd 15
    odd 17
    odd 19
    odd 21
    odd 23
    odd 25
    odd 27
    odd 29
    odd 31
    odd 33
    odd 35
    odd 37
    odd 39
    odd 41
    odd 43
    odd 45
    odd 47
    odd 49
    

    【讨论】:

    • 谢谢你的解释,对我很有帮助
    猜你喜欢
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2011-06-23
    相关资源
    最近更新 更多