【戒焦戒躁,can win】Linux--IO缓冲区

fopen干了啥

书接上文,下面这些代码都是系统函数调用,不能即用C库函数,又用系统函数。

举个例子。fopen 打开文件返回的是FILE*类型,不能直接将其传入到write。因为 write接收的文件描述符是int类型。事实上,FILE*类型内部封装了一个文件描述符,文件描述符就是文件描述符指针数组的下标,通过该文件描述符就可以找到对应文件,从而进行读写。更改数组的指向,就可以实现重定向。

其中,fopen首先申请struct File结构体空间,然后返回其地址,也就是 struct File*,然后调用系统调用函数open得到文件描述符,将文件描述符填充到结构体中。
在这里插入图片描述

缓冲区

运行下面这段代码的效果,看上去是程序先休眠后打印。但实际上,程序是先打印,后睡眠,因为打印未显示出来,所以从运行效果上看,就是先睡眠后打印。
在这里插入图片描述
造成这种结果的原因是数据先被缓存起来了。

缓冲策略

  • 无缓冲
  • 行缓冲: 只有当内存行缓冲区打满或者遇到\n,系统才会把缓冲区内的数据刷新。
  • 全缓冲:对磁盘文件写入时采用的策略。需要将缓冲区写满,才能写到磁盘文件中。

之所以要有缓冲区,这是由计算机体系决定的。外设由于是机械设备,它的输入输出速度跟不上中央处理器的速度,因此就需要在输入输出时先将数据缓存到内存中,再进行后续处理。

父子进程与缓冲区的关联

在这里插入图片描述
运行上面代码,将结果显示到显示器上,得到的结果为三个函数以此的打印结果。
在这里插入图片描述
当运行时将打印结果重定向,结果如下。
在这里插入图片描述
造成这两种结果的原因是:当我们往显示器上打印,缓冲策略采用的是行刷新。因为往显示器打印字符串的函数调用都带有\n,所以在fork之前,程序已经打印并刷新,缓冲区内没有数据,不存在写时拷贝。

当重定向到一个磁盘文件时,缓冲策略变成全缓冲。此时\n对全缓冲没有影响,字符串只打印不刷新,字符串存在缓冲区中,当执行fork时,进程结束要刷新修改缓冲区内的数据,因为父子进程要保持独立性,所以在子进程也会拷贝一份缓冲区的数据,即写时拷贝

因此调用C库函数就分别打印了两次。而系统调用write是没有缓冲区的,只打印一次。那么,这个缓冲区就是C语言提供的,若是系统提供的,那么write也应该有缓冲区,打印两次,两者构成矛盾。

需要注意的是内存分为用户空间和系统空间,语言本身提供的缓冲区在用户空间中,为了将此缓冲区数据写入磁盘文件中,还需经过系统缓冲区,系统缓冲区将数据最后写到磁盘文件。

系统调用:文件重定向

在这里插入图片描述
这里使用dup2系统调用函数,使得1号文件描述符的指向和fd的指向一致,也就是文件描述符指针数组下标不变,内容变了,结果就是两者都指向同一个struct file,由此实现了重定向。可以看到往1号文件描述符写数据,数据写进了文本内。
在这里插入图片描述

进一步理解:Linux 一切皆文件

一切皆文件也可以认为是一切皆struct file。Linux设备都会被描述成这种结构。这样通过readwrite函数调用就可以实现对设备的输入和输出。不同的设备有不同的输入和输出方式,因此这时就可以采用函数指针实现多态,让不同设备有不同的读写方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Schuyler Hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值