2019-08-13
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
#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来获取一些进程的进程号,并打印出来,以分析程序的运行 ^_^