用户进程是运行在用户空间的,不能直接 *** 作内核缓冲区的数据。 用户进程进行系统调用的时候,会由用户态切换到内核态,待内核处理完之后再返回用户态。例如:read把数据从内核缓冲区复制到进程i/o缓冲区,write把数据从进程i/o缓冲区复制到内核缓冲区,内核缓冲区再和磁盘之间的交换。薯衫简
程序和磁盘交换细节
用户i/o缓冲区的类型:
全缓冲
此种类型的缓冲只有在缓冲区满的时候才会调用实际的文件 IO 进入内核态 *** 作。除了涉及到终端设备文件的流,其它文件流默认基本都是全缓冲。
行缓冲
此种类型的缓冲在缓冲区满或者遇到 \n 的时候才会调用实际的文件 IO 进数裤入内核态 *** 作。当流涉及到终端设备的时候就是行缓冲,比如标准输入流和标准输出流。如果对标准输入流或者输出流进行重定向到某个文件的时候,该流就是全缓冲的。
无缓冲
没有缓冲区。直接调用文件 IO 进入内核态 *** 作。标准错误流默认就是无缓冲的。
2、下边举一个例子加深理解:
每个进程都有一个标准i/o缓冲,缓冲区是使用malloc申请的,所以缓冲区是在堆区
#include <stdio.h>
#include <stdlib.h>
int main() {
塌渗 for (int i = 0 i < 2 i++) {
fork()
printf("*")
}
return 0
}
i=0时:主进程子进程都会在各自的缓冲区输入一个*,
i=1时:新创建的两个进程会从父进程复制缓冲区,会继承下来一个*,自己在往缓冲区塞一个*,因此各自都有两个*。同时i=0时创建的两个进程也会往各自的缓冲区塞一个*。这时各个进程的缓冲区都有两个*,所以一共8个*。
shell中经常会使用到IO重定向,
0、1、2为文件描述符在默认情况下,分别表示进程的标准输入、标准输出、标准错误输出。I/O重定向可以将茄戚弯这些标准的输入输出重定向到其他文件上,例如上面语句作用是,将标准输出仔派和标准错误输出重定向到文件/dev/null这个黑洞文件里面,即不输出
shell常用的方法如下
说明io重定向先简单说明内核如何表示一个打开的文件,在一个进程的内核结构中维护着两张表表示该进程已打开的文件(这里简单说明,并不严谨),可以如下所示
用户层打开一个文件内核将分配一个fd和file结构并填入进程的fd和file表中,fd和file保持对应的关系,io重定向即可以修改这种对应关系,内核提供dup和dup2等系颤闷统调用完成这项功能
已dup2为例
2>&1对应调用dup2(1,2)
调用后fd和file的对应关系将变为如下形式,其中file2标识为灰色表面内核可能关闭file2结构
了解上述原理后简单说明以下两者的区别,通过实例图应该比较清楚
对于上述原理理解后对应IO重定向应该有比较形象的理解了,但是还是存在一些盲点,即被重定向的文件描述符是一个未打开过的文件,还是一个打开的文件,如果已打开,被重定向后,源文件是否会被关闭,带着这些疑问,看看内核源码是怎么实现的吧,下述源码对应内核版本为2.6.18
通过源码可以比较清楚的发现
dup(m,n)中
1、n可以是一个全新的文件描述符即还未分配给已打开的文件,此时内核将分配该fd,并把该对应关系执行m执行的file结构,并对该file结构引用+1
2、n也可以是一个已经被分配给打开文件的描述符,此时内核将重新将该fd的指向改为m指向的file结构,引用+1,之后对原先n指向的file结构尝试关闭
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)