一个fork问题的思考
来源:互联网 发布:mac地址绑定错误 编辑:程序博客网 时间:2024/06/10 15:16
问题一: 下面程序一共输出多少个"-"
#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(void){ int i; for(i=0; i<2; i++){ fork(); printf("-"); } return 0;}
按照fork()机制的运行逻辑,其输出应该是6个"-",但是这段程序的输出结果是8个"-"
在弄清楚这个问题之前,需要了解fork()系统调用的几个特性:
- fork()系统调用是用于创建子进程的系统调用,一次调用,两次返回(大家可以分析一下fork系统调用的汇编代码,看它是如何实现两次返回的),如果返回0,则是子进程;如果返回值大于0,则是父进程(返回值是子进程的pid)
- 还需要注意的一个细节就是:在fork()系统调用处,真个父进程的执行环境会全部复制给子进程,其中包括指令、变量值、程序调用栈、环境变量、缓冲区等。
上面的执行结果之所以会输出8个"-",就是因为printf("-")语句是带有buffer的,printf("-")会将"-"放到该进程的buffer中,当进行fork()系统调用时,自己程会复制父进程buffer中的内容,从而多了两个"-"
另外,linux中的设备分为块设备和字符设备,一般情况下块设备是有缓冲的,而字符设备是没有缓冲的。
如果将上述代码修改为:
printf("-\n") ;
或是
printf("-") ;fflush(stdout) ;
最终的输出结果就是6个,因为程序遇到"\n",或是EOF,或是缓冲区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。由于标准输出是行缓冲,所以遇到"\n"时会刷出缓冲,而对于磁盘这个块设备来说,"\n"并不会引起缓冲区刷出操作, 因为磁盘是全缓冲,可以使用setvbuf来设置缓冲区大小,或是用fflush刷新缓存。因此如果将程序的输出重定向到文件的话,第一种代码修改方案依旧会输出8个"-",而第二种方案会正常输出6个
下面以图的形式展现整个fork的过程:
上图中相同颜色的表示同一个进程,使用pstree -p | grep fork
命令可以打印出进程之间的关系,如下图所示:
这样,对于printf("-");这样的语句,我们就可以清楚的知道,那个子进程复制到父进程缓冲区的内容而导致多次输出了。如下图所示,加了阴影和双边框的两个子进程导致了多次输出
问题二:下面代码的字符串是一起输出还是一部分一部分地输出?
printf("----");sleep(5);printf("++++");sleep(5);printf("\n");
代码执行结果是:所有字符串等到执行printf("\n")时才一起输出,这也就是说printf("----")只是将字符串放到缓冲区中,在执行printf("\n")或是程序结束前并没有输出出来。有了这个概念之后,下面的问题三就比较好理解了
问题三:下面代码的输出是什么?
#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main(void){ int i; for(i=0; i<2; i++){ printf("-"); printf("ppid=%d, pid=%d, i=%d \n", getppid(), getpid(), i); fork(); } return 0;}
这段代码的输出结果依旧是8个"-",解析过程如下图所示:
执行到程序结束时,系统中有图示的最下面的4个进程,图中相同进程我已使用相同颜色标识,虽然这4个进程在i=2时均没有执行printf("-"),但是其缓冲区内均由字符串"--",因此在进程结束的时候,系统会强制将缓冲区的内容刷新到输出设备上,所以会产生8个"-".
如果将上述代码修改为:
printf("-\n") ;
或是
printf("-") ;fflush(stdout) ;
程序的输出是3个"-",也就是图中进程树的第一层和第二层执行的printf("-")的结果。
Reference: http://coolshell.cn/articles/7965.html
- 一个fork问题的思考
- 一个fork的思考
- 一个fork的问题
- 一个问题的思考
- 关于fork 的一个小问题
- fork与vfork遇到的一个问题
- 一个问题引发的思考
- 一个字符串问题的思考
- 一个问题引起的思考
- 一个字符串问题的思考 .
- 一个问题引发的思考
- 一个余数问题的思考
- 指针的一个问题思考
- 一个粗心的问题引发的思考
- 一个简单的问题引发的思考
- 一个关于概率的问题的思考
- fork的一个例子
- fork()的一个实例
- gradle打包android工程
- 调整hadoop 集群datanode 物理内容大小
- Mingw下python C api编译
- 浏览器工作原理
- A - Following Orders(11.3.1))
- 一个fork问题的思考
- php学习要点
- mac系统如何显示和隐藏文件 和 删除SVN隐藏文件
- 【水输入】#52 A. Bar
- poj2499
- BUPT Summer Journey #test9 A
- UVALive 5025 Arranging Your Team dfs
- 使用MJRefresh上下拉刷新时的问题
- 两种方法求单链表逆序