【问题标题】:forks in C - exerciseC 中的叉子 - 练习
【发布时间】:2010-03-22 16:12:15
【问题描述】:

在 C 的丛林中用叉子砍树时,我尝试重复并学习更高级的用法和选项。但愚蠢的是,我找到了一个应该非常简单的示例,因为我之前使用过叉子,甚至编写了一些代码,但是完全看不懂。

来了:

main() {
 if (fork() == 0) {
  if (fork() == 0) {
   printf("3");
  }
  else if ((wait(NULL)) > 0) {
   printf("2");
  }
 }
 else {
  if (fork() == 0) {
   printf("1");
   exit(0);
  }
  if (fork() == 0) {
   printf("4");
  }
 }
 printf("0");
 return 0;
}

可能的解决方案是:

  1. 3201040
  2. 3104200
  3. 1040302
  4. 4321000
  5. 4030201
  6. 1403020

其中 2、5 和 6 是正确答案。

首先,输出中不应该有四个零吗? 第二......一个人是如何找到解决方案的?在纸上做了将近一个小时,我什至不明白为什么给定的解决方案比错误的解决方案更正确(nr3 除外,因为它不能以 2 结尾,因为后面必须跟着 0)。

谁能提供一些好的解释?

编辑:

发现这个here 看看 2009 年的 pdf。人们现在可以停止发布关于这是一项家庭作业的帖子并真正尝试提供帮助吗?如果没有,请找一些其他的话题来消磨你的时间。谢谢!

【问题讨论】:

    标签: c fork


    【解决方案1】:

    我认为应该有 4 个零,如果我运行你的代码,这就是我看到的......

    分析这一点的一个好方法是绘制一个像这样的图表 - 我将叉子显示为*,父进程水平继续,子进程在下方,这样每个单独的进程都在单独的行上:

    ----*----*----*----0----exit (return from main)
        |    |    |
        |    |    +----4----0----exit (return from main)
        |    |
        |    +----1----exit (explicitly)
        |
        +-----*----wait----2----0----exit (return from main)
              |
              +----3----0----exit (return from main)
    

    现在很容易看出,由于wait(),您必须看到3 之后是0之前看到2 之后是0

    【讨论】:

    • ...并打印出 8 位数字,而不是答案中的 7 位
    • @Matthew Slattery:感谢分享这种分析此类程序的巧妙方法!
    【解决方案2】:

    由于在程序打印 1 之后的 exit 语句,输出中只有三个零。该语句立即结束该过程。 Ed:不,实际上应该是4个零;我忽略了原来的过程。我不知道为什么答案中没有四个零。

    在分析问题的答案时,您通常需要了解的是:

    1. 每次调用 fork() 时,您都会创建一个新进程,并且旧进程也会继续,两者都是从同一点开始
    2. 您可以通过检查fork 的返回值来判断您是在“旧进程”还是“新进程”中。如果您在新流程中,它将为 0(假),如果您在旧流程中,则为非零(真)。
    3. 调用wait(NULL) 将暂停当前进程的执行,直到从它派生出的一个进程完成。
    4. (最重要)不同进程中的语句可以相对于彼此以任何顺序执行。但是,单个进程中的语句当然必须保持顺序。

    详细说明 4,假设您有两个进程,一个打印“abc”,另一个打印“xyz”。诸如“abxcyz”、“xaybcz”或“xyabcz”之类的输出是可能的,因为序列 abc 和 xyz 都是按顺序出现的。但是,输出“abzcxy”是不可能的,因为 z 不可能出现在 x 之前,因为它们都来自同一个进程,并且打印它们的语句以另一个顺序出现。

    【讨论】:

    • '2' 和 '3' 分叉各打印一个零,'1' 分叉不打印零,最后一个分叉打印两个零。这不是 4 吗?
    • "...如果您在旧进程中,则返回非零 (true)" - 记得检查 -1 表示 fork 失败(内存不足/命中进程限制)
    • 嗨,感谢您的解释和见解,但您错过了我已经写过我知道分叉并且已经编写了一些项目的代码,所以这并没有真正的帮助。我知道退出语句退出并且不会打印额外的 0,因为没有它,它将是 5 个零?
    • 实际编译运行这个(gcc 4.4.1 and kernel 2.6.31-17-generic)会打印4个0。
    【解决方案3】:

    他们假设当你调用 wait(NULL) 时,整个 '3' fork 都会执行。这包括在该分叉的末尾打印“0”。因此,答案 1 和 4 不正确,因为它们在“2”之前没有“0”。

    至于为什么没有四个'0',我不知道。

    【讨论】:

      【解决方案4】:

      首先,您必须选择的选项不是所有可能的输出排列。相反,它们只是其中的一小部分。查看源代码,我们可以注意到以下几点来消除可能性:

      1. 打印“1”的分支然后执行exit(0),而不继续打印“0”。所以输出中只有三个 0。也是因为这个原因,最后一个字符不能是 0 或 1。
      2. 在第二次分叉之后,我们在打印“2”之前为孩子wait(NULL)。这意味着我们等待的孩子总是会在打印 2 之前先打印 3,然后再打印 0。

      这些确实是关于这个问题唯一可以明确地说的事情。这意味着任何正确答案都必须以 0 或 1 结尾,并且必须在 2 之前同时具有 3 和 0。满足这些条件的唯一答案是 2、5 和 6。

      【讨论】:

      • 我错过了一些东西。有 4 个 fork,这意味着 5 个进程,对吧?一个进程在第 13 行退出,剩下的 4 个继续到 main 函数的末尾。为什么只打印了 3 个零?
      • 你是对的,这是一个错误。 (给出的原始解决方案中有一个错误。)
      猜你喜欢
      • 2022-06-14
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 2013-03-07
      • 1970-01-01
      • 2020-10-21
      • 2015-01-02
      • 1970-01-01
      相关资源
      最近更新 更多