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,提升设备利用率。

相关推荐
小尧嵌入式2 小时前
【Linux开发二】数字反转|除数累加|差分数组|vector插入和访问|小数四舍五入及向上取整|矩阵逆置|基础文件IO|深入文件IO
linux·服务器·开发语言·c++·线性代数·算法·矩阵
代码游侠2 小时前
ARM开放——阶段问题综述(一)
arm开发·笔记·嵌入式硬件·学习·架构
你的秋裤穿反了2 小时前
笔记13--------报警记录
笔记
@小博的博客2 小时前
Linux 中的编译器 GCC 的编译原理和使用详解
linux·运维·服务器
电饭叔2 小时前
has_solution = False 是什么 费马大定律代码化和定理《计算机科学中的数学》外扩学习3
学习·算法
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [drivers][base]faux
linux·笔记·学习
wheeldown2 小时前
【Linux】TCP协议【2】: 从 echo 到远程命令执行:Linux TCP 服务器的并发与安全实践
linux·服务器·tcp/ip
后来后来啊2 小时前
2026.1.19学习笔记
笔记·学习·算法
鄭郑2 小时前
【Wordpress笔记02】文章分类与标签
笔记