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存入各自文件中 问题: ...
随机推荐
- Hibernate五大核心接口简介
所有的Hibernate应用中都会访问Hibernate的5个核心接口. Configuration接口:配置Hibernate,根启动Hibernate,创建SessionFactory对象. Se ...
- 肠道型(enterotype)简介
An enterotype is a classification of living organisms based on its bacteriological ecosystem in the ...
- Confluence 6 从外部目录中同步数据如何工作
下面是有关缓存功能的一些摘要信息: 用户和用户组的缓存信息保存在应用程序的数据库中. 当你连接一个新的外部目录到系统中的时候,一个同步任务将会启动被,并且在后台运行拷贝所有需要的用户和用户组信息,以及 ...
- Jamie and Binary Sequence (changed after round) CodeForces - 916B (贪心)
链接 大意: 求将n划分为k个2的幂的和, 且最大幂最小,字典序尽量大 比较简单的贪心练习题, 但放在div2的B题感觉偏难了..... 先只考虑最大幂最小, 首先注意到直接按n的二进制划分即可得到最 ...
- TCP客户端与服务器的实现
为了更容易理解,我们举一个小例子来说明服务器与客户端之间的连接过程. 有一个饭店,饭店里有服务员,服务员用于招待客人 特别要注意的是:要记住相关函数的各个参数都是什么,什么时候返回SOCKET_ERR ...
- LeetCode 318. Maximum Product of Word Lengths (状态压缩)
题目大意:给出一些字符串,找出两个不同的字符串之间长度之积的最大值,但要求这两个字符串之间不能拥有相同的字符.(字符只考虑小写字母). 题目分析:字符最多只有26个,因此每个字符串可以用一个二进制数来 ...
- xhost + 的作用
xhost 是用来控制X server访问权限的. 通常当你从hostA登陆到hostB上运行hostB上的应用程序时, 做为应用程序来说,hostA是client,但是作为图形来说, 是在hostA ...
- ScoketTimeout Exception浅析
以前都是用WebService的方式调用服务方的服务,此次直接调用别人的http服务. 使用的客户端是org.apache.http.client.HttpClient. 用的httpclient-4 ...
- Kubernetes设计架构
官方文档:https://www.kubernetes.org.cn/doc-11 Kubernetes集群包含有节点代理kubelet和Master组件(APIs, scheduler, etc), ...
- AIOps探索:基于VAE模型的周期性KPI异常检测方法——VAE异常检测
AIOps探索:基于VAE模型的周期性KPI异常检测方法 from:jinjinlin.com 作者:林锦进 前言 在智能运维领域中,由于缺少异常样本,有监督方法的使用场景受限.因此,如何利用无监 ...