fork调用实验-缓冲区相关
先看下面一段代码:
#include <unistd.h>
#include <stdio.h> int globvar = ;
char buf[] = "a write to stdout\n"; int main()
{
int var;
pid_t pid; var = ;
if(write(STDOUT_FILENO, buf, sizeof(buf) - ) != sizeof(buf) - )
{
printf("write error\n");
}
printf("before fork\n"); //没有调用flush冲刷缓冲区 if((pid = fork()) < )
{
printf("fork error\n");
}
else if(pid == )
{
globvar++;
var++;
}
else
{
sleep();
} printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
return ;
}
编译并执行上述程序,结果如下:
pid=2500的输出是子进程,其它三条输出都是父进程的输出,第13行的write函数是不带缓冲区的,这里的缓冲区说的是用户空间的缓冲区,但是在内核中还是有page cache缓冲区的,这两个缓冲区是不一样的,也就是不管写多少数据,write是不会将数据缓冲到用户空间的,而是直接将数据写到内核中的page cache中。而printf是带用户空间缓冲区的,printf输出的数据会先写到由C库维护的用户空间缓冲区中,当然,也跟一些参数有关,会涉及到行缓冲、全缓冲、无缓冲,后面会讲到。
父进程执行fork的时候,会将其持有的资源复制给子进程,内核中的page cache是不会复制的,因为page cache是跟文件绑定的,而不是与单个进程相关的。也就是说一个文件会对应一些page cache,但是可以有多个进程往这些page cache中写数据或者读数据,内核不会为每个进程都维护一份page cache。
父进程复制给子进程包括一些文件描述符,它们共享文件表项,也就是指向同一个file数据结构,而且共享同一个文件偏移量。也包括用户空间的其它一些资源。
printf会维护进程的用户空间缓冲区,我们可以认为它就是每个进程用户态地址空间中堆上的一些存储区域,这些区域在fork时是会复制给子进程的。在上面的输出中,我们看到a write to stdout直接写进了内核的page cache,但是before fork是由printf输出的,会先写到用户空间的缓冲区,执行fork后,用户空间缓冲区也会复制给子进程(当然缓冲区中的数据也会复制),子进程应该也会输出brfore fork才对,但是上图并没有相应的输出。原因是这样的,printf输出到标准输出时是行缓冲的,往用户空间写数据时,遇到换行符就会一次性将所有数据全部刷到内核的page cache中,这样用户空间缓冲区就没有数据了,所以复制给子进程时缓冲区中是空的。这样子进程没有输出before fork也就可以解释了。
下面我们换一种执行方式:
可以看到,这次子进程输出了before fork,因为这次将标准输出重定向到了一个文件,printf输出到一个文件时是全缓冲的,也就是只有写满用户空间的缓冲区之后才会一次性冲刷到内核page cache中,而before fork不足以写满用户空间缓冲区,所以在执行fork的时候,父进程的用户空间缓冲区中是有数据的,这些数据一并复制给了子进程。
任何一个进程退出时,都会冲刷用户空间的缓冲区,因此两个进程都输出了before fork。main函数的最后调用了return,编译器会自动加上exit(0),exit是C库中对系统调用_exit的封装,也就是在exit中会冲刷用户空间的缓冲区,如果直接调用_exit,则可能不会有冲刷缓冲区的动作,而是直接进入内核进行操作。
将main函数最后的return 0改为_exit(0),再次执行,结果如下:
输出到标准输出的情况下和上一个程序没有区别,因为printf执行完之后,数据会立刻冲刷到内核page cache,而page cache中的数据在进程退出时是一定会写到最终的设备的。
再次重定向标准输出到temp.out,执行结果如下:
这次只输出了一行,printf输出到文件时是全缓冲的,也就是必须写满用户空间缓冲区才会冲刷,而本程序中并不会写满这个缓冲区,而_exit退出时也不会冲刷用户空间缓冲区,所以printf输出的数据都无效了。
小知识:行缓冲、全缓冲、无缓冲是对用户空间的缓冲区说的,也叫标准IO缓冲,不是对内核中的page cache说的,page cache是由内核来管理的,对用户是透明的。
fork调用实验-缓冲区相关的更多相关文章
- ASP.NET Web API与Owin OAuth:调用与用户相关的Web API
在前一篇博文中,我们通过以 OAuth 的 Client Credential Grant 授权方式(只验证调用客户端,不验证登录用户)拿到的 Access Token ,成功调用了与用户无关的 We ...
- fork调用的底层实现
fork调用的内核实现: http://www.cnblogs.com/huangwei/archive/2010/05/21/1740794.html http://blog.csdn.net/he ...
- 操作系统(1)——X86-32硬件介绍、实验环境相关配置、uCore部分技巧介绍
实验环境 本文假设已经创建虚拟机并配置好Ubuntu 16.04(网上太多教程了,所以这里就不赘述了). X86-32硬件介绍 x86指的是80386这种机器(一种32位CPU,在早期得到了广泛的应用 ...
- Linux安全实验缓冲区溢出
缓冲区溢出实验: 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据缓冲器和返回地址的暂时关 ...
- fork()调用使子进程先于父进程被调度
由于内核使用写时复制机制,fork之后父子进程是共享页表描述符的,如果让父进程先执行,那么有很大几率父进程会修改共享页表指向的数据,那么内核此时必须给父进程分配并复制新的页表供父进程修改使用,那么如果 ...
- Integer缓冲区相关问题--valueOf()方法
今天在学习过程中了解到一个现象,代码如下: Integer num1 = 100; Integer num2 = 100; System.out.println(num1==num2?true:fal ...
- ASP.NET Web API与Owin OAuth:调用与用户相关的Web API(非第三方登录)
授权完成添加属性 ClaimsIdentity oAuthIdentity = await CreateAsync(user/*userManager*/, OAuthDefaults.Authent ...
- 深入理解php的输出缓冲区(output buffer)
这篇文章是翻译自Julien Pauli的博客文章PHP output buffer in deep,Julien是PHP源码的资深开发和维护人员.这篇文章从多个方面讲解了PHP中的输出缓冲区以及怎么 ...
- 文件缓冲区在fork后复制
场景:父进程trace进程A,当A进程fork子进程B时,让父进程也fork子进程去trace子进程B,用于trace的进程将被trace的进程发生的系统调用号通过fprintf存入各自文件中 问题: ...
随机推荐
- c++ 判断容器A是否是容器B的子集,如果是,返回true(includes)
#include <iostream> // cout #include <algorithm> // includes, sort using namespace std; ...
- 转载:Nginx负载均衡的5种策略
nginx可以根据客户端IP进行负载均衡,在upstream里设置ip_hash,就可以针对同一个C类地址段中的客户端选择同一个后端服务器,除非那个后端服务器宕了才会换一个. nginx的upstre ...
- MongoDB(课时14 正则运算)
3.2.4.9 正则运算 如果想实现模糊查询,必须使用正则表达式,而且正则表达式使用的语言是Perl兼容的正则表达式的形式. 要实现正则使用,则按照如下的定义格式: 基础语法:{key : 正则标记} ...
- CAS-自旋锁
自旋锁 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环. 获取锁的线程一直处于 ...
- 监督学习--k近邻算法
2017-07-20 15:18:25 k近邻(k-Nearest Neighbour, 简称kNN)学习是一种常用的监督学习方法,其工作机制非常简单,对某个给定的测试样本,基于某种距离度量找出训练集 ...
- 20170324xlVBA最简单分类计数
Sub NextSeven_CodeFrame() Application.ScreenUpdating = False Application.DisplayAlerts = False Appli ...
- android--------自定义视频控件(视频全屏竖屏自动切换)
android播放视频也是常用的技术,今天分享一个自定义视频控件,支持自定义控制 UI,全屏播放, 可以实现自动横竖屏切换的控件,跟随手机的位置而,重力感应自动切换横竖屏. 效果图: 代码下载Gi ...
- Android之RecyclerView实现时光轴
做项目的过程中有个需求需要时光轴,于是网上找了部分资料 ,写了个案例,现在分享给大家. 如图: activity_main.xml <?xml version="1.0" e ...
- Vue自动化工具(Vue-CLI)
一.组件的概念 1.概念 组件(Component)是自定义封装的功能.在前端开发过程中,经常出现多个网页的功能是重复的,而且很多不同的网站之间,也存在同样的功能. 而在网页中实现一个功能,需要使用h ...
- RMQ板子
对于RMQ这种静态最值询问, 用线段树的话查询过慢, 一般用ST表预处理后O(1)查询, 下以最大值查询为例, 这里假定$n$不超过5e5 void init() { Log[0] = -1; REP ...