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存入各自文件中 问题: ...
随机推荐
- idea 2018注册码(激活码)永久性的
2DZ8RPRSBU-eyJsaWNlbnNlSWQiOiIyRFo4UlBSU0JVIiwibGljZW5zZWVOYW1lIjoiY24gdHUiLCJhc3NpZ25lZU5hbWUiOiIiL ...
- shell 跳出循环
跳出循环 break命令 例: #!/bin/bash while : do echo -n "输入 1 到 5 之间的数字:" read aNum case $aNum in 1 ...
- IntelliJ IDE 开发Java GUI 入门
j主要对java 的GUI相关知识进行简单的介绍和总结,整个博客按照创建一个java GUI的顺序进行介绍,期间穿插讲解用到的java Swing的布局.控件等相关知识.本博客所进行的讲解及工程的创建 ...
- Java之美[从菜鸟到高手演变]系列之博文阅读导航
随着博文越来越多,为博客添加一个导航很有必要!本博客将相继开通Java.CloudFoundry.Linux.Ruby等专栏,都会设立目录,希望读者朋友们能更加方便的阅读! 在阅读的过程中有任何问题, ...
- windows 2012 R2安装SqlServer2016提示缺少KB2919355
补丁的安装顺序如下: 1, 首先安装 Windows2012R2更新的先决条件KB2919442.2,按照如下顺序安装后续KB文件.顺序:clearcompressionflag.exe.KB2919 ...
- c# 获取方法所在的命名空间 类名 方法名
平时我们在记录日志的时候难免会需要直接记录当前方法的路径,以便查找,但是每次都输入方法名称非常的繁琐,同时如果修改了方法名称也要去手动修改日志内容,真的是劳命伤财啊,所以有了如下方法则可解决我们的大难 ...
- 手把手教你开发jquery插件
I have said that i dislike jQuery UI’s unified API, so i want to get the instance of the component a ...
- EFS 你应该知道的事
需要备份或者还保留这个路径 %USERPROFILE%\AppData\Roaming\Microsoft\Crypto\RSA certmgr.msc 个人证书导出你开始使用EFS加密后的证书 ci ...
- IE6不兼容hover已解决
新建一个csshover.htc文件,一下是csshover.htc内容 <public:attach event="ondocumentready" onevent=&qu ...
- CF1082G Petya and Graph
题意 定义图权 = 图中边权总和 - 图中点权总和(空图的图权=0),求 n 个点 m 条边的无向图最大权子图. 把边看成点,这个点与两个原图中的点连边.直接最小割求最大闭合子图即可.