为什么这个程序打印"分叉!" 4次?

 手机用户2602939201 发布于 2022-12-13 17:11

为什么这个程序打印"分叉!"4次?

#include 
#include 

int main(void) {

  fork() && (fork() || fork());

  printf("forked!\n");
  return 0;
}

gsamaras.. 205

一个来自,main()另外三个来自每个fork().

请注意,这三个forks()都将被执行.你可能想看一下ref:

返回值

成功完成后,fork()将向子进程返回0,并将子进程的进程ID返回给父进程.两个进程都将继续从fork()函数执行.否则,-1应返回到父进程,不应创建子进程,并设置errno以指示错误.

请注意,进程ID不能为零,如规定在这里.


那真的发生了什么?

我们有:

fork() && (fork() || fork());

因此,第一个fork()将返回父级非零进程ID,而它将返回0到子进程.这意味着逻辑表达式的第一个fork将在父进程中被评估为true,而在子进程中它将被评估为false,并且由于短路评估,它将不会调用剩余的两个fork().

因此,现在我们知道将至少获得两个打印件(一个来自main,一个来自1st fork()).

现在,fork()父进程中的第二个将被执行,它确实会向父进程返回一个非零值,在子进程中返回一个零值.

所以现在,父进程不会继续执行到最后一次fork()(由于短路),而子进程将执行最后一个fork,因为第一个操作数||是0.

这意味着我们将再获得两次打印.

结果,我们总共获得了四张照片.


短路

这里,短路基本上意味着如果&&的第一个操作数为零,则不评估其他操作数.在相同的逻辑上,如果是||的操作数 是1,那么其余的操作数不需要评估.发生这种情况是因为其余的操作数不能改变逻辑表达式的结果,因此不需要执行它们,因此我们节省了时间.

见下面的例子.


处理

请记住,父进程会创建后代进程,从而创建其他进程等等.这导致了流程的层次结构(或者可以说是树).

考虑到这一点,值得看看这个类似的问题,以及这个答案.


描述性图像

我猜这个数字也可以提供帮助.我认为fork()每次通话时返回的pid 为3,4和5.

fork节点 请注意,有些fork()s在它们上方有一个红色X,这意味着由于逻辑表达式的短路评估,它们不会被执行.

fork()顶部的s不会被执行,因为运算符的第一个操作数&&是0,因此整个表达式将导致0,因此执行其余操作数时没有本质&&.

fork()底部将不会被执行,因为它的第二个操作数||,在其第一个操作数是一个非零数字,因此表达式的结果已经被评估为真,无论第二个操作数是什么.

在下一张图片中,您可以看到流程的层次结构: 流程层次结构 基于上图.


短路的例子

#include 

int main(void) {

  if(printf("A printf() results in logic true\n"))
    ;//empty body

  if(0 && printf("Short circuiting will not let me execute\n"))
    ;
  else if(0 || printf("I have to be executed\n"))
    ;
  else if(1 || printf("No need for me to get executed\n"))
    ;
  else
  printf("The answer wasn't nonsense after all!\n");

  return 0;
}

输出:

A printf() results in logic true
I have to be executed


Jean-Baptist.. 84

fork()一个在调用进程中返回一个非零值(称之为p0),在子节点中返回0(称之为p1).

在p1中,采用短路&&并且过程调用printf并终止.在p0中,该过程必须评估表达式的其余部分.然后它fork()再次调用,从而创建一个新的子进程(p2).

在p0中fork()返回一个非零值,并且采用shortcircuit ||,因此进程调用printf并终止.

在p2中,fork()返回0,因此||的其余部分 必须评估,这是最后一个fork(); 这导致为p2创建一个孩子(称之为p3).

P2然后执行printf并终止.

然后P3执行printf并终止.

printf然后执行4 秒.

6 个回答
  • 对于所有的downvoters来说,这是一个合并但不同的问题.责备SO.谢谢.

    您可以将问题分解为三行,第一行和最后一行都只是将进程数加倍.

    fork() && fork() || fork();
    

    操作员是短路的,所以这就是你得到的:

           fork()
          /      \
        0/        \>0
     || fork()     && fork()
         /\            /   \
        /  \         0/     \>0
       *    *     || fork()  *
                    /   \
                   *     *
    

    所以这总共是4*5 = 20个进程,每个进程打印一行.

    注意:如果由于某种原因fork()失败(例如,您对进程数有一些限制),它返回-1然后您可以得到不同的结果.

    2022-12-13 17:12 回答
  • 执行fork() && (fork() || fork()),会发生什么

    每个fork给出2个进程,分别是值pid(父)和0(子)

    第一叉:

    父返回值是pid not null =>执行 && (fork() || fork())

    第二个fork父值是pid not null停止执行||part => printforked

    second fork child value = 0 =>执行 || fork()

    第三叉父母打印 forked

    第三叉儿童版画 forked

    子返回值为0停止执行&& part =>打印 forked

    总计:4 forked

    2022-12-13 17:12 回答
  • 这段代码:

    fork();
    fork() && fork() || fork();
    fork();
    

    为自己获得20个进程,并且将获得20次Printf.

    并为

    fork() && fork() || fork();
    

    printf将共计5次.

    2022-12-13 17:12 回答
  • 一个来自,main()另外三个来自每个fork().

    请注意,这三个forks()都将被执行.你可能想看一下ref:

    返回值

    成功完成后,fork()将向子进程返回0,并将子进程的进程ID返回给父进程.两个进程都将继续从fork()函数执行.否则,-1应返回到父进程,不应创建子进程,并设置errno以指示错误.

    请注意,进程ID不能为零,如规定在这里.


    那真的发生了什么?

    我们有:

    fork() && (fork() || fork());
    

    因此,第一个fork()将返回父级非零进程ID,而它将返回0到子进程.这意味着逻辑表达式的第一个fork将在父进程中被评估为true,而在子进程中它将被评估为false,并且由于短路评估,它将不会调用剩余的两个fork().

    因此,现在我们知道将至少获得两个打印件(一个来自main,一个来自1st fork()).

    现在,fork()父进程中的第二个将被执行,它确实会向父进程返回一个非零值,在子进程中返回一个零值.

    所以现在,父进程不会继续执行到最后一次fork()(由于短路),而子进程将执行最后一个fork,因为第一个操作数||是0.

    这意味着我们将再获得两次打印.

    结果,我们总共获得了四张照片.


    短路

    这里,短路基本上意味着如果&&的第一个操作数为零,则不评估其他操作数.在相同的逻辑上,如果是||的操作数 是1,那么其余的操作数不需要评估.发生这种情况是因为其余的操作数不能改变逻辑表达式的结果,因此不需要执行它们,因此我们节省了时间.

    见下面的例子.


    处理

    请记住,父进程会创建后代进程,从而创建其他进程等等.这导致了流程的层次结构(或者可以说是树).

    考虑到这一点,值得看看这个类似的问题,以及这个答案.


    描述性图像

    我猜这个数字也可以提供帮助.我认为fork()每次通话时返回的pid 为3,4和5.

    fork节点 请注意,有些fork()s在它们上方有一个红色X,这意味着由于逻辑表达式的短路评估,它们不会被执行.

    fork()顶部的s不会被执行,因为运算符的第一个操作数&&是0,因此整个表达式将导致0,因此执行其余操作数时没有本质&&.

    fork()底部将不会被执行,因为它的第二个操作数||,在其第一个操作数是一个非零数字,因此表达式的结果已经被评估为真,无论第二个操作数是什么.

    在下一张图片中,您可以看到流程的层次结构: 流程层次结构 基于上图.


    短路的例子

    #include <stdio.h>
    
    int main(void) {
    
      if(printf("A printf() results in logic true\n"))
        ;//empty body
    
      if(0 && printf("Short circuiting will not let me execute\n"))
        ;
      else if(0 || printf("I have to be executed\n"))
        ;
      else if(1 || printf("No need for me to get executed\n"))
        ;
      else
      printf("The answer wasn't nonsense after all!\n");
    
      return 0;
    }
    

    输出:

    A printf() results in logic true
    I have to be executed
    

    2022-12-13 17:12 回答
  • 我喜欢已经提交的所有答案.也许如果你在printf语句中添加了一些变量,你就会更容易看到发生了什么.

    #include<stdio.h>
    #include<unistd.h>
    
    int main(){
    
       long child = fork() && (fork() || fork());
       printf("forked! PID=%ld Child=%ld\n", getpid(), child);
       return 0;
    }
    

    在我的机器上它产生了这个输出:

    forked! PID=3694 Child = 0
    forked! PID=3696 Child = 0
    forked! PID=3693 Child = 1
    forked! PID=3695 Child = 1
    

    2022-12-13 17:12 回答
  • fork()一个在调用进程中返回一个非零值(称之为p0),在子节点中返回0(称之为p1).

    在p1中,采用短路&&并且过程调用printf并终止.在p0中,该过程必须评估表达式的其余部分.然后它fork()再次调用,从而创建一个新的子进程(p2).

    在p0中fork()返回一个非零值,并且采用shortcircuit ||,因此进程调用printf并终止.

    在p2中,fork()返回0,因此||的其余部分 必须评估,这是最后一个fork(); 这导致为p2创建一个孩子(称之为p3).

    P2然后执行printf并终止.

    然后P3执行printf并终止.

    printf然后执行4 秒.

    2022-12-13 17:12 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有