【问题标题】:How to use fork() in an if statement如何在 if 语句中使用 fork()
【发布时间】:2012-09-07 23:15:59
【问题描述】:

有人可以向我解释一下fork() != 0 是什么意思吗?据我了解,我认为这意味着如果 fork 不是假的?或者如果 fork 是真的那么......我不明白 Fork() 如何是真或假,因为它只是创建了一个进程的副本到父子进程中。另外如果一个程序在哪里说if (Fork() == 0)是什么意思?

 #include "csapp.h"

 int main(void)
 {
     int x = 3;

     if (Fork() != 0)
         printf("x=%d\n", ++x);

     printf("x=%d\n", --x);
     exit(0);
 }

【问题讨论】:

  • 你读过一些关于fork的文档吗?谷歌搜索它带来了很多解释它是如何工作的,以及你如何使用它的返回值。
  • 在父母和孩子中都调用exit 是非常糟糕的做法。例如,如果进程在调用Fork 之前缓冲了文件输出,则父进程和子进程在调用exit 时都会刷新该输出。

标签: c fork


【解决方案1】:

fork() 如果失败则返回 -1,如果成功则在父节点中返回分叉子节点的 pid,在子节点中返回 0。所以if (fork() != 0)测试是否是父进程。

【讨论】:

    【解决方案2】:

    Fork 为子进程返回 0,子进程的进程 id 给父进程。因此通常代码有 if(fork){ }else 代码。这意味着 if 中的代码将仅在父级中执行。

    更好的处理方法是

     pid = fork()
     if(pid){
      // I am parent. Let us do something that only the parent has to do
     }else{
     // I am child. Let us do something only the child has to do
     }
     // This code is common to both
    

    子 pid 可能有助于稍后等待或与父 pid 分离。

    【讨论】:

      【解决方案3】:

      来自 fork() 手册:

      Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent
           process.  Otherwise, a value of -1 is returned to the parent process, no child process is created, and the global variable errno is set to indi-
           cate the error.
      

      代码执行后你有两个执行线程。在 if 语句中你有父进程的线程,在 else 语句中你有子进程的线程。

      if ( fork() ) { 
          printf("I am the parent!\n"); 
      } else {
          printf("I am the child\n");
      }
      

      编辑

      为了澄清的目的:fork 启动一个进程,它有一个线程、内存并且可能有其他资源。我尝试(似乎没有成功)通过添加“线程”一词来强调执行流程。 但是,决不能说“父”与“父进程的线程”中的“线程”有关。

      当然,我的答案还有待改进,但我认为这里已经有足够好的答案了。

      【讨论】:

      • 对不起@Useless,但我没有说它们不是进程:“父进程的线程”是指每个进程上的(主/唯一)执行线程。它可能误导了你,但我试图强调两个执行流程。
      • 我重复了将“child's thread”更改为“child process' thread”的进程词以改进它。谢谢@Useless。
      【解决方案4】:

      来自man fork

      返回值

      成功时,在父进程中返回子进程的PID, 并且在孩子中返回 0。失败时,-1 在 parent,没有创建子进程,并且设置了适当的errno。

      假设成功,fork 返回两次:一次在父项中,一次在子项中。


      好的,我对 OP 造成了伤害:我不知道 csapp.h 来自哪里,但如果是 this one,那么它对您没有任何帮助。我猜它是 POSIX 上的一个薄包装器(例如 fork() 附近),但也许也适用于其他平台?

      因为你在Fork() 之前提到了fork(),所以我认为后者是一个错字,而它实际上是一个库函数。

      如果您一直直接使用fork(),那么期望您查看联机帮助页是合理的。 由于您使用的是某个库提供的 Fork() 函数,因此该库确实应该记录它,但似乎没有。


      标准(非csapp)用法是:

      pid_t child = fork();
      if (child == -1) {
          printf("fork failed - %d - %s\n", errno, strerror(errno));
          exit(-1);
      }
      if (child) {
          printf("I have a child with pid %d, so I must be the parent!\n", child);
      } else {
          printf("I don't have a child ... so I must be the child!\n")
      }
      exit(0);
      

      【讨论】:

      • 如果成功,并在两个(否则相同)进程中返回......每个进程的返回值是多少?
      • 当 fork 返回时,您有两个并行运行的进程,每个进程都有自己的 x 副本 ...例如,child 在我上面的示例代码中是一个变量,但每个进程获得具有不同值的单独副本
      • csapp.h 来自教科书,包装器的文档在书中:amazon.com/Computer-Systems-Programmers-Perspective-Edition/dp/…
      【解决方案5】:

      让我们尝试不同的解释......当函数启动时有1个进程,这个进程有一个int x = 3

      一旦你点击了这行代码:

      if (fork() != 0)
      

      现在,假设 fork() 有效,我们有两个进程。它们都有相同的执行空间,它们都将运行相同的代码(在一定程度上),但孩子将获得自己的 x 副本来玩。

      fork() 将返回一个 0 给子进程,所以从子进程的角度来看,函数的其余部分是这样的:

      printf(("x=%d\n", --x);
      exit(0);
      

      另一方面,父进程将从 fork() 命令返回一个有效值,因此它将执行:

      printf("x=%d\n", ++x);
      printf("x=%d\n", --x);
      exit(0);
      

      此时的输出将是任何人的猜测......You can't tell if parent or child will run first

      但如果我们假设父级点击++x 是下一个操作,那么输出是:

      x=4
      x=3
      x=2
      

      因为父母和孩子都会点击--x。 (父母的x在++x之后是4,最后是3。孩子的x是3,最后是2)

      【讨论】:

        【解决方案6】:

        我建议将 if 替换为 switch,因为有 3 种可能的结果:

        #include <sys/types.h>
        #include <unistd.h>
        
        pid_t pid;
        
        switch ((pid = fork ())) {
        case -1: /* error creating child. */
          break;
        case 0:  /* I am the child process. */
          break;
        default: /* I am the parent process. */
          break;
        }
        

        【讨论】:

          猜你喜欢
          • 2019-07-06
          • 2020-04-02
          • 2017-08-30
          • 1970-01-01
          • 2015-01-26
          • 2020-06-23
          • 2020-12-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多