fork() && fork() || fork();
(2012-05-01 12:58:49)
哪天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 <unistd.h>
#include <stdio.h>
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 <stdio.h>
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来获取一些进程的进程号,并打印出来,以分析程序的运行
^_^
喜欢
0
赠金笔
加载中,请稍候......