Linux学习笔记(十二)--用户缓冲区

用户缓冲区

在Linux操作系统中,用户缓冲区是应用程序在用户空间内维护的一块内存区域,用于临时存储待写入文件或网络的数据,或从文件/网络读取的数据。它的主要目的是减少系统调用次数,提高I/O效率。

用户缓冲区的类型

先来一段代码研究一下

复制代码
#include<stdio.h>
#include<string.h>

int main()
{
    const char *msg0="hello printf\n";
    const char *msg1="hello fwrite\n";
    const char *msg2="hello write\n";

    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout);
    write(1, msg2, strlen(msg2));

    fork();

    return 0;
}

当代码运行之后结果是

复制代码
hello printf
hello fwrite
hello write

但当我们对进程实现输出重定向(./hello > file)时,结果变成

复制代码
hello write
hello printf
hello fwrite
hello printf
hello fwrite

两次结果不一致,这是因为printf和fwrite函数都输出了两次,write只输出了一次。这与fork有关,C库函数的缓冲机制与系统调用存在显著差异。库函数如printffwrite等,在输出到文件时采用全缓冲,而输出到显示器时通常采用行缓冲,当发生重定向时,缓冲方式会发生改变。相比之下,系统调用write没有内置缓冲机制,会立即执行写入操作。这种差异在实际编程中会带来重要的行为差异。例如,当程序调用fork()创建子进程时,由于写时拷贝机制的存在,父子进程会共享缓冲区的数据,这可能导致输出结果与预期不符。

所以用户缓冲区的类型有三种,分别是:

(1)全缓冲:缓冲区填满时刷新(如普通文件)。
(2)行缓冲:遇到换行符\n时刷新(如终端标准输出stdout)。
(3)无缓冲:立即输出(如标准错误stderr)。

用户缓冲区和内核缓冲区的关系:

用户缓冲区与内核缓冲区(如页缓存Page Cache)是独立但协作的两层:用户缓冲区位于进程地址空间,由应用程序或标准库管理。而内核缓冲区位于内核空间,用于缓存磁盘数据或网络数据,减少物理I/O。

数据流示例:

复制代码
应用程序数据 → 用户缓冲区 → write()系统调用 → 内核缓冲区 → 磁盘/网络

用户缓冲区与内核缓冲区区别:

用户缓冲区刷新(如fflush())仅将数据复制到内核缓冲区,不保证落盘。内核缓冲区由内核管理,通过fsync()或定时刷新(通常30秒)写入磁盘。

缓冲区的控制方法:

(1) 标准库缓冲控制

setvbuf():设置缓冲区模式(全缓冲/行缓冲/无缓冲)及自定义缓冲区。

fflush():强制刷新指定文件的用户缓冲区到内核。

setbuf()/setbuffer():简化版缓冲区设置。

(2) 系统调用绕开用户缓冲区

使用read()/write()等系统调用时,数据直接在内核和用户空间传递,不经过标准库缓冲区(但仍有内核缓冲区参与)。

(3) 强制落盘

fsync(fd):确保内核缓冲区数据写入物理磁盘。

fdatasync(fd):类似fsync,但只刷新数据部分(不更新元数据)。

用户缓冲区的核心作用

减少系统调用开销 :每次系统调用(如read()/write())都需要从用户态切换到内核态,涉及上下文保存、权限检查等开销。通过缓冲区累积数据后批量操作,可大幅降低切换频率。(示例 :若每次写1字节,调用write()100次需100次系统调用;而用1KB缓冲区累积数据后写入,仅需1次系统调用。)

适配不同I/O粒度:应用程序的数据处理单位(如逐字符)可能与内核或磁盘的块大小(如4KB)不匹配。缓冲区作为中间层,可累积小数据到合适粒度再提交。

优化硬件访问:磁盘或网络设备更适合大块数据传输。缓冲区积累足够数据后,内核可合并多次小写入为单次大块I/O,提升设备利用率。

相关推荐
chlk1231 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑1 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件1 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号2 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash2 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI2 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行3 天前
Linux和window共享文件夹
linux
木心月转码ing3 天前
WSL+Cpp开发环境配置
linux
崔小汤呀4 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应4 天前
vi编辑器使用
linux·后端·操作系统