当前位置: 首页 > news >正文

五种 IO 模式的简单介绍 -- 阻塞 IO,非阻塞 IO,信号驱动 IO,IO 多路复用,异步 IO

目录

1. 同步阻塞 IO(Blocking IO)

2. 同步非阻塞 IO(Non-Blocking IO)

2.1 同屋非阻塞 IO 介绍

2.2 错误码介绍

2.3 非阻塞 IO demo 代码

3. 信号驱动 IO(Signal Driven IO,SIGIO)

4. IO 多路复用(IO Multiplexing) 

5. 异步 IO(Asynchronous IO,AIO)


        IO 的过程可以分为等待数据和拷贝数据两个阶段

1. 同步阻塞 IO(Blocking IO)

        同步阻塞 IO:进程发起 IO 操作后会被阻塞,知道 IO 操作完成才返回,期间无法处理其他任务。阻塞 IO 是最常见的 IO 模型。

        如上图所示,进程调用 recvfrom 向内核发送读请求(读取文件、网络接收数据),内核等待数据就绪(数据从磁盘加载到内存、网络数据到达),数据就绪后,内核将数据拷贝到进程(用户)缓冲区,进程解除阻塞并处理数据。

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>int main()
{char buffer[1024];while(true){std::cout << "请输入数据: ";fflush(stdout); // 立即将内核缓冲区的数据刷新到标准输出中ssize_t n = read(0, buffer, sizeof(buffer));if (n > 0){buffer[n - 1] = 0;std::cout << "读取的数据:" << buffer << std::endl;}elsebreak;}r

        如上图,标准输入默认情况下是阻塞模式的,所以每次都会等待用户进行输入之后才进行数据处理。 

2. 同步非阻塞 IO(Non-Blocking IO)

2.1 同屋非阻塞 IO 介绍

        同步非阻塞 IO:进程发起 IO 请求后立即返回,通过轮询方式查询 IO 操作是否完成,不会阻塞进程

        非阻塞 IO 往往需要轮询的方式反复尝试读写文件描述符,这对 CPU 来说是较大的浪费。

        如上图,进程调用 recvfrom 发起读请求,第一次内核中无数据就绪,则返回,然后通过循环调用 recvfrom 发起第二次读请求,内核中依旧无数据就绪,继续返回,知道有数据就绪后,内核将数据拷贝到进程缓冲区中,并进行处理。 

        fcntl 函数:fcntl(file control)是 Linux 系统中用于操作文件描述符属性的核心系统调用,提供了对文件、套接字、管道等 IO 资源的高级控制能力。

#include <unistd.h>
#include <fcntl.h>int fcntl(int fd, int cmd, ...);

        fd:目标文件描述符。

        cmd:操作命令,决定 fcntl 的具体功能。

        ...:可变参数,根据 cmd 不同可能为整数、指针或结构体。        

        返回值:成功时根据 cmd 返回不同值,失败返回 -1, 并设置 errno。 

        下列介绍部分 cmd 参数:

        (1)F_GETFL:返回 fd 的状态标志(如 O_EDONLY、O_NONBLOCK)

        (2)F_SETFL:修改 fd 状态标志,常用标志包括:
                O_NONBLOCK:设置为非阻塞 IO

                O_APPEND:设置为追加模式。

                O_DIRECT:绕过内核缓冲区,直接 IO。

                O_ASYNC:启动信号驱动 IO 通知。

2.2 错误码介绍

        read 函数用于从文件描述符中读取数据,返回读取的字节数,错误时返回 -1,并设置 errno(错误码)。

       下列介绍部分调用 read 函数时发生错误设置的错误码。

       (1)EAGAIN:表示操作无法立即完成,需要重试(通常用于文件描述符设置为非阻塞时)。

       (2)EWOULDBLOCK:与 EAGAIN 本质相同,是其别名,不同系统可能定义不同,在 POSXI 标准中,EWOULDBLOCK 常用于套接字操作。

        (3)EINTR:表示阻塞的系统调用被信号(如 SIGINT、SIGTERM)中断,导致调用未完成而返回错误。

2.3 非阻塞 IO demo 代码

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <fcntl.h>void SetNonBlock(int fd)
{int fl = fcntl(fd, F_GETFL);if (fl < 0){perror("fcntl");return;}fcntl(fd, F_SETFL, fl | O_NONBLOCK);
}int main()
{SetNonBlock(0);  // 设置标准输入为非阻塞char buffer[1024];while(true){ssize_t n = read(0, buffer, sizeof(buffer));if (n > 0){buffer[n - 1] = 0;std::cout << buffer << std::endl;sleep(1);}else if (n < 0) // 底层数据没有准备好,数据读取不算出错{// 1. 读取出错或者数据没有就绪if (errno == EAGAIN || errno == EWOULDBLOCK)    // 错误码{std::cout << "数据没有就绪... " << std::endl;sleep(1);// 其他业务// ....continue;}else if (errno == EINTR)continue;else    // 其他错误break;}elsebreak;}return 0;
}

3. 信号驱动 IO(Signal Driven IO,SIGIO)

        信号驱动 IO:进程通过注册信号处理函数,当 IO 操作就绪时,内核向进程发送信号(如 SIGIO),进程通过信号回调处理 IO 事件

        如上图,进程将 fd 设置为信号驱动模式,并绑定信号处理函数,内核等待数据就绪后,向进程发送 SIGIO 信号,进程捕获信号,在信号处理函数中完成 IO 操作。 

4. IO 多路复用(IO Multiplexing) 

        IO 多路复用:通过一个进程监控多个文件描述符,当其中一个或多个准备就绪时,进程被唤醒并处理对应的 IO 操作

        在 Linux 中有三种机制进行 IO 多路复用:select、poll、epoll。

        select:监控 fd(文件描述符)集合,通过遍历 fd 判断就绪状态fd 数量受限于 FD_SETSIZE(默认 1024)。该机制支持跨平台,但是效率低,并且监控 fd 数量有限,适合小规模连接。

        poll:用链表存储 fd,无数量限制,但仍需遍历所有 fd 进行就绪状态的判断。该机制监控的 fd 没数量限制,效率比 select 高(但是仍需遍历所以 fd,效率也不是特别高)。

        epoll:事件驱动模型,内核维护就绪 fd 列表仅通知就绪事件(LT/ET 模式)。Linux 高新能机制,支持百万级连接,适用于高并发场景(如 Nginx、Redis)。

        上述三种机制在之后进行详细介绍。

5. 异步 IO(Asynchronous IO,AIO)

        异步 IO:进程发起 IO 请求后立即返回,内核在 IO 操作完成(包括数据拷贝)后通知进程,全程无需进程主动干预

        如上图,进程通过 aio_read 向内核提交 IO 请求,指定回调函数或事件通知方式。内核负责数据读取和拷贝当用户缓冲区,完成后通过信号、回调或事件通知进程,进程处理 IO 结构,无需关注中间过程。 

        

http://www.lqws.cn/news/507079.html

相关文章:

  • 2025.6.16-实习
  • 网络安全攻防:2025年新型钓鱼攻击防御指南
  • JVM(12)——详解G1垃圾回收器
  • 使用预训练权重在YOLO模型上训练新数据集的完整指南
  • 深入理解RAG:大语言模型时代的知识增强架构
  • 解析云计算虚拟化基石:KVM、QEMU与Libvirt的协同
  • SpringBoot - 整合 Redis 实现数据分布式缓存
  • 通过环境变量管理多版本JDK8、11、17并安装idea编译器
  • 攻防世界-MISC-MeowMeowMeow
  • BRAIN LANG:新发现!大脑网络重新调整以补偿在嘈杂环境中的听力困难
  • 【MV】编排4:基于时间线数据的密度突变检测和密度平滑算法
  • Springboot项目中使用手机号短信验证码注册登录实现
  • wpf单文件打包还有 一些dll打包不进去?
  • JS核心操作符:从基础到ES6+
  • phpstudy apache伪静态.htaccess文件置空丢失问题解决
  • iostat中的util原理
  • 从iOS到Flutter:我的转型之路与技术成长启示
  • matplotilb实现对MACD的实战
  • TDengine 技术参数配置大全
  • Docker 报错“x509: certificate signed by unknown authority”的排查与解决实录
  • 什么是 OA 系统?OA 系统要具备什么样的功能?
  • jsoncpp-src-0.5.0编译
  • Python Bug 修复案例分析:编码问题导致程序出现bug 两种修复方法
  • Redis哈希表Rehash全解析:扩容缩容背后的渐进式智慧
  • SpringBoot 自动化部署实战:CI/CD 整合方案与避坑全指南
  • 相较于传统购物,AR 购物在便利性方面体现在哪些维度?​
  • IDC报告AR/VR市场反弹Meta份额超半,谷歌/微美全息精准卡位AR/AI眼镜市场机遇
  • 快速搭建系统原型,UI界面,有哪些高效的AI工具和方法
  • 数智助农 金融兴乡:中和农信双轮驱动农业现代化实践
  • 重医等利用纯生信在iMeta(中科院1区|IF33.2)发表:多组学联合分析西部五省母婴队列数据