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存入各自文件中 问题: ...
随机推荐
- 附加题找bug
private: void ReSize(int sz) { ) { return; } if(maxSize != sz) { T *arr = new T[sz]; if(arr == NULL) ...
- css3转盘
此效果涉及到 : 1. css 画图形 2. css3 动态效果 3. 贝塞尔曲线 用法 <style> .lds-hourglass { display: inline-block; p ...
- air for android 使用ANE来获取安卓手机IMEI号
一首页创建一个ANE文件 1 使用FlashBuilder 或者Eclipse 创建一个新的android项目 A 创建文件Extension.java package com.dabing. ...
- Lua面向对象 --- 多继承
工程目录结构: ParentMother.lua: ParentMother = {} function ParentMother:MortherName() print("Morther ...
- Python版本微信跳一跳,软件配置
一.安装python3的环境: 直接从python官方网站下载python3的安装包,直接安装. 记得将python3放到PATH环境变量中,安装的过程中在该配置地方打钩就可以了. 如果安装的过程中出 ...
- Linux下安装Phantomjs
1. 安装linux系统的软件包 先来看一下官方网站的提示: Note: For this static build, the binary is self-contained. There is n ...
- linux系统方面的知识
1.什么是Linux? 组成部分:硬件.内核.lib库.应用程序 硬件:工作中真正工作的组成部分是硬件 linux内核(kernel):管理硬件 Linux团队管理的版本 lib库:封 ...
- 20170706wdVBA保存图片到本地API
Private Type GUID Data1 As Long Data2 As Integer Data3 As Integer Data4(0 To 7) As Byte End Type Pri ...
- Vue.js Client-Side Storage;( Web Storage/localStorage)
原文:https://cn.vuejs.org/v2/cookbook/client-side-storage.html LocalStorage (api) my code pen :https:/ ...
- Up and Down the Tree CodeForces - 1065F (树形dp)
链接 题目大意:给定$n$结点树, 假设当前在结点$v$, 有两种操作 $(1)$移动到$v$的子树内任意一个叶子上 $(2)$若$v$为叶子, 可以移动到距离$v$不超过$k$的祖先上 初始在结点$ ...