问题导入
文件流输出直接向显示器和重定向文件有不一样的表现
分别向显示器文件输出四个语句,最后fork创建子进程。
当程序运行时和程序重定向到文件中,输出的内容不一样。
重定向时c库函数(printf,fprintf,fwrite)调用了两次,而系统调用write函数只调用了一次
关闭对应的虚拟文件,只有系统调用可以输出
屏蔽系统调用,同时关闭显示器对应的虚拟文件
运行程序没有任何输出,只有系统调用有输出。如果先close(1)再系统调用也没有任何输出。
解释问题
问题二的解释
调用c的库函数是存在一个用户级别的缓冲区,当缓冲区的数据刷新时会把数据刷新到内核级别的缓冲区,而write函数可以直接把数据输入内核级别的缓冲区,而close的作用关闭fd为1虚拟文件。
相当于fprintf/printf和fwrite刷新不到内核级别的缓冲区了,而write可以直接写入。所以只有write的输出有结果。
那么就是说,只要把数据刷新到内核级别的缓冲区就能输入到显示器中。
目前我们认为,只要将数据刷新到内核,数据就可以刷新到硬件
用户级别缓冲区的刷新策略
无缓冲---直接刷新
行缓冲---缓冲区不刷新,直到碰到\n ---显示器
全缓冲---缓冲区写满才刷新---普通文件写入
进程退出也会刷新
显示器的文件的刷新方案是行刷新,所以printf执行完就立即遇到\n
因此我们只要加上\n让缓冲区立刻刷新,保证在close代码前就把数据刷新进入内核中,就能把信息输出到屏幕上。
所以在原代码中,库函数调用的语句都在缓冲区,没有立刻刷新,当进程退出时刷新缓冲区时,已经运行了close语句,此时缓冲区已经没办法找到内核了。
刷新的本质就是将数据通过fd=1+write接口写入到内核中.
有了以上铺垫我们就可以解释为什么库函数调用exit会刷新缓冲区,系统调用_exit不会刷新缓冲区
对于exit而言,他是包含用户级别的缓冲区而内核的,而_exit只知道内核,无法接触上一级的缓冲区也就无法刷新。
解释问题一
重定向意味着文件流是输入到普通文件,而不是显示器,是全缓冲策略。\n不会再刷新缓冲区,而是进程结束时刷新缓冲区。
而进程前运行fork函数,对数据进行写时拷贝。产生两个缓冲区。
注意write的输入不经过这个缓冲区,所以不会重复。
以fprintf举例。
缓冲区存在意义
体现封装的特性,对于库函数来说,不需要关注数据是如何刷新到硬件上的,只用把数据刷新到缓冲区即可
配合格式化,如将int型等都转换为字符串