2019-08-13

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

 (2012-05-01 12:58:49)

转载

标签: 

it

哪天chinaunix看帖子,看到一个有趣的题目,今天思考了下,记录一下。

int main(int argc, char* argv[])

{

 fork();

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

 fork();

}

不算main这个进程自身,到底创建了多少个进程啊?

分析:

1. 第一个fork(), 第五个fork(), 肯定会执行,故总进程数= 2 * (fork() && fork()|| fork()) *2。

2. 关键就是fork2() && fork3()|| fork4() 产生来了多少个进程 。

 每个fork()返回值要么等于0,要么大于0(c语言中无bool,非0在逻辑运算中即是1)。

 我已经把fork() 从2到4标号。

 执行用伪代码表示,逻辑如下:

 if(fork2 返回> 0)

 {

 if(fork3 返回> 0)

 ; //1个进程

 else(fork3 返回== 0)

fork4 //2个进程

 }

 else

{

 fork4//2个进程

 }

所以共计 2*5*2 -1 = 19个进程。

#include

#include

int main()

{

 fork();

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

 fork();

 sleep(100);

 return 0;

}

 据说是EMC的一道选择题,感觉挺有意思的,这道题主要考了两个知识点,一是逻辑运算符运行的特点;二是对fork的理解。这道题在Linux(Ubuntu 9.10)输出如下:

ecy@ecy-geek:~/C++$ ps

 PID TTY TIME CMD

1833 pts/0 00:00:00 bash

2088 pts/0 00:00:00 fork

2089 pts/0 00:00:00 fork

2090 pts/0 00:00:00 fork

2091 pts/0 00:00:00 fork

2092 pts/0 00:00:00 fork

2093 pts/0 00:00:00 fork

2094 pts/0 00:00:00 fork

2095 pts/0 00:00:00 fork

2096 pts/0 00:00:00 fork

2097 pts/0 00:00:00 fork

2098 pts/0 00:00:00 fork

2099 pts/0 00:00:00 fork

2100 pts/0 00:00:00 fork

2101 pts/0 00:00:00 fork

2102 pts/0 00:00:00 fork

2103 pts/0 00:00:00 fork

2104 pts/0 00:00:00 fork

2105 pts/0 00:00:00 fork

2106 pts/0 00:00:00 fork

2107 pts/0 00:00:00 fork

2108 pts/0 00:00:00 ps

 从2088到2107这20个进程,除了一个主进程,其余19个进程都是fork出来的。刚开始我看到这个结果感觉有点奇怪,接着在纸上分析了一下,算得 头都晕了,最后才算出正确值来了。恩,使用二叉树画图分析是比较好的方法。现在我想通过等价的方法改写上面的代码,使之更易懂。

 如果有一个这样的表达式:

cond1 && cond2 || cond3

 这句代码会怎样执行呢?首先看一个例子,代码如下:

#include

int main()

{

 0 && printf("1, not run!\n");

 1 && printf("2, must run!\n");

 0 || printf("3, must run!\n");

 1 || printf("4, not run!\n");

 return 0;

}

程序运行的输出如下:

ecy@ecy-geek:~/C++$ ./cond

2, must run!

3, must run!

 由此可知,&&和||都是快速与和快速或,上面"cond1 && cond2 || cond3"的执行有下面几种情况:

 一、cond1为假,那就不判断cond2了,接着判断cond3

 二、cond1为真,这又要分为两种情况:

 1、cond2为真,这就不需要判断cond3了

 2、cond2为假,那还得判断cond3

 根据这个分析,最上面的代码可以改写成一下形式:

int main()

{

 //第一个fork必须执行

 fork();

 //fork() && fork() || fork()

 //第一个fork也必须执行

 int ret1 = fork();

 //cond1 && cond2 || cond3

 //父进程返回值不为0,即cond1为真

 if(ret1 != 0)

 {

  int ret2 = fork();

  //cond2为假,必须判断cond3

  if(ret2 == 0)

  {

   fork();

  }

 }

 else //cond1为假时,必须判断cond3

 {

  fork();

 }

 //最后一个fork必须执行

 fork();

 sleep(100);

 return 0;

}

程序执行结果如下:

ecy@ecy-geek:~/C++$ ps

 PID TTY TIME CMD

1833 pts/0 00:00:00 bash

2432 pts/0 00:00:00 fork

2433 pts/0 00:00:00 fork

2434 pts/0 00:00:00 fork

2435 pts/0 00:00:00 fork

2436 pts/0 00:00:00 fork

2437 pts/0 00:00:00 fork

2438 pts/0 00:00:00 fork

2439 pts/0 00:00:00 fork

2440 pts/0 00:00:00 fork

2441 pts/0 00:00:00 fork

2444 pts/0 00:00:00 fork

2445 pts/0 00:00:00 fork

2446 pts/0 00:00:00 fork

2447 pts/0 00:00:00 fork

2448 pts/0 00:00:00 fork

2449 pts/0 00:00:00 fork

2450 pts/0 00:00:00 fork

2451 pts/0 00:00:00 fork

2452 pts/0 00:00:00 fork

2453 pts/0 00:00:00 fork

2454 pts/0 00:00:00 ps

 符合预期,改成这种形式的代码之后就可以方便地插入一些代码,比如通过getpid来获取一些进程的进程号,并打印出来,以分析程序的运行 ^_^

你可能感兴趣的:(2019-08-13)