Linux系统--五种IO模型

news2024/9/27 5:44:20

1、简介

  Linux IO 模型根据实现的功能可以划分为为阻塞 IO、 非阻塞 IO、 信号驱动 IO, IO 多路复用和异
步 IO。 根据等待 IO 的执行结果进行划分, 前四个 IO 模型又被称为同步 IO,如下图:
在这里插入图片描述

2、详细介绍

2.1 阻塞IO

  在阻塞IO模型中,调用read或write时,如果没有数据可读或写,进程会被挂起,直到数据可用。这是最简单的IO模型。以阻塞读为例: 进程进行 IO 操作时(如 read 操作), 首先会发起一个系统调用, 从而转到内核空间进行处理, 内核空间的数据没有准备就绪时, 进程会被阻塞, 不会继续向下执行, 直到内核空间的数据准备完成后, 数据才会从内核空间拷贝到用户空间, 最后返回用户进程, 由用户空间进行数据的处理, 如下图所示:
在这里插入图片描述
  示例代码如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    char buffer[100];
    int fd = open("file.txt", O_RDONLY);
    
    // 阻塞调用
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
    if (bytes_read < 0) {
        perror("read error");
    } else {
        printf("Read %zd bytes: %s\n", bytes_read, buffer);
    }

    close(fd);
    return 0;
}

2.2 非阻塞IO

  在非阻塞IO模型中,调用read或write时,如果没有数据可读或写,返回-1,errno设置为EAGAIN。进程不会被挂起。和阻塞 IO 模型不同, 非阻塞 IO 进行 IO 操作时, 如果内核数据没有准备好, 内核会立即向进程返回 err, 不会进行阻塞; 如果内核空间数据准备就绪, 内核会立即把数据返回给用户空间的进程, 如下图所示:
在这里插入图片描述
  示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main() {
    char buffer[100];
    int fd = open("file.txt", O_RDONLY | O_NONBLOCK);
    
    // 非阻塞调用
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
    if (bytes_read < 0) {
        if (errno == EAGAIN) {
            printf("No data available\n");
        } else {
            perror("read error");
        }
    } else {
        printf("Read %zd bytes: %s\n", bytes_read, buffer);
    }

    close(fd);
    return 0;
}

2.3 IO复用

  通常情况下使用 select()、 poll()、epoll()函数实现 IO 多路复用。 这里以 select 函数为例进行讲解, 使用时可以对 select 传入多个描述符, 并设置超时时间。 当执行 select 的时候, 系统会发起一个系统调用, 内核会遍历检查传入的描述符是否有事件发生(如可读、 可写事件) 。 如有, 立即返回, 否则进入睡眠状态, 使进程进入阻塞状态, 直到任何一个描述符事件产生后(或者等待超时) 立刻返回。 此时用户空间需要对全部描述符进行遍历, 以确认具体是哪个发生了事件, 这样就能使用一个进程对多个 IO 进行管理, 如下图所示:
在这里插入图片描述
  示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>

int main() {
    int fd1 = open("file1.txt", O_RDONLY);
    int fd2 = open("file2.txt", O_RDONLY);
    
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(fd1, &readfds);
    FD_SET(fd2, &readfds);

    // 等待文件描述符就绪
    int max_fd = (fd1 > fd2) ? fd1 : fd2;
    int retval = select(max_fd + 1, &readfds, NULL, NULL, NULL);

    if (retval == -1) {
        perror("select error");
    } else if (retval) {
        if (FD_ISSET(fd1, &readfds)) {
            printf("file1.txt is ready for reading\n");
        }
        if (FD_ISSET(fd2, &readfds)) {
            printf("file2.txt is ready for reading\n");
        }
    } else {
        printf("No file descriptors are ready\n");
    }

    close(fd1);
    close(fd2);
    return 0;
}

2.4 信号驱动IO

  信号驱动 IO 顾名思义与信号相关。 系统在一些事件发生之后, 会对进程发出特定的信号,而信号与处理函数相绑定, 当信号产生时就会调用绑定的处理函数。 例如在 Linux 系统任务执行的过程中可以按下 ctrl+C 来对任务进行终止, 系统实际上是对该进程发送一个 SIGINT 信号,该信号的默认处理函数就是退出当前程序。具体到 IO 模型上, 可以对 SIGIO 信号注册相应的信号处理函数, 并打开对应描述符的信号驱动。 每当有 IO 数据产生时, 系统就会发送一个 SIGIO 信号, 进而调用相应的信号处理函数,从而在这个处理函数中对数据进行读取, 如下图 所示:
在这里插入图片描述
  示例代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

void handler(int sig) {
    printf("Data is available to read!\n");
}

int main() {
    signal(SIGIO, handler);
    
    int fd = open("file.txt", O_RDONLY | O_NONBLOCK);
    fcntl(fd, F_SETFL, O_ASYNC); // 设置异步IO
    
    // 允许进程接收SIGIO信号
    fcntl(fd, F_SETOWN, getpid());

    // 主循环,保持进程运行
    while (1) {
        pause(); // 等待信号
    }

    close(fd);
    return 0;
}

2.5 异步IO

  在异步IO模型中,进程提交IO请求后可以继续执行,IO操作在后台完成,完成后操作系统会通知进程。aio_read 函数常常用于异步 IO, 当进程使用 aio_read 读取数据时, 如果数据尚未准备就绪就立即返回, 不会阻塞。 若数据准备就绪就会把数据从内核空间拷贝到用户空间的缓冲区中,然后执行定义好的回调函数对接收到的数据进行处理。
在这里插入图片描述
  示例代码:

#include <stdio.h>
#include <aio.h>
#include <fcntl.h>
#include <string.h>

int main() {
    struct aiocb cb;
    char buffer[100];
    int fd = open("file.txt", O_RDONLY);

    memset(&cb, 0, sizeof(struct aiocb));
    cb.aio_fildes = fd;
    cb.aio_buf = buffer;
    cb.aio_nbytes = sizeof(buffer);

    // 提交异步读取
    if (aio_read(&cb) == -1) {
        perror("aio_read error");
    }

    // 检查IO是否完成
    while (aio_error(&cb) == EINPROGRESS) {
        // 可以执行其他操作
        printf("Doing other work...\n");
        sleep(1);
    }

    // 获取结果
    ssize_t bytes_read = aio_return(&cb);
    printf("Read %zd bytes: %s\n", bytes_read, buffer);

    close(fd);
    return 0;
}

3、总结

  Linux中的五种IO模型主要包括阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO。

  • 阻塞IO:调用read或write时,如果没有数据可读或写,进程会被挂起,直到操作完成。这种模型简单易用,但在高并发场景下效率低。
  • 非阻塞IO:在调用read或write时,如果没有数据可读或写,返回-1,errno设置为EAGAIN。这样,进程可以继续执行其他任务,但需要轮询或管理状态。
  • IO复用:使用select、poll或epoll等系统调用,可以监视多个文件描述符,等待其中一个或多个就绪。这种方法适合处理大量并发连接,提高了效率。
  • 信号驱动IO:通过设置信号处理程序,进程在文件描述符就绪时会收到信号。这种模型减少了轮询,但处理信号的复杂性增加。
  • 异步IO:提交IO请求后,进程可以继续执行,IO操作在后台完成。当完成后,操作系统会通知进程。这种方式能有效利用CPU资源,但实现较复杂。

  这些模型各有优缺点,选择时需根据具体应用场景进行权衡。

参考资料:《itop-3568开发板驱动开发指南v2.0》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker容器常用命令详解

Docker容器常用命令&#xff0c;我们经常使用&#xff0c;又经常忘记&#xff0c;今天我们系统分析一下&#xff1a; 1、查看运行的进程 #列出所有运行的容器 sudo docker ps#列出所有容器&#xff0c;包括运行和停止的 docker ps -a #列出所有容器&#xff0c;并过滤 docker…

大数据Hologres(一):Hologres 简单介绍

文章目录 Hologres 简单介绍 一、什么是实时数仓 Hologres 二、产品优势 1、专注实时场景 2、亚秒级交互式分析 3、统一数据服务出口 4、开放生态 5、MaxCompute查询加速 6、计算存储分离架构 三、应用场景 搭建实时数仓 四、产品架构 1、Shared Disk/Storage &am…

深入探索linux的零拷贝(zero-copy):底层技术原理与代码实现

前言 I/O 或输入/输出通常意味着中央处理器(CPU) 与外部设备&#xff08;如磁盘、鼠标、键盘等&#xff09;之间的读写。在深入研究零拷贝之前&#xff0c;有必要指出磁盘 I/O&#xff08;包括磁盘设备和其他块导向设备&#xff09;和网络 I/O之间的区别。 磁盘 I/O 的常用接…

mysql安装教程(新手版)

本教程不需要手动设置配置文件&#xff0c;比较简单&#xff0c;适合新手&#xff0c;过程需联网。 1.找到mysql官网 mysql官网 一.mysql的安装 1.界面如下图&#xff0c;点击箭头所指。 2.选择mysql版本&#xff0c;系统&#xff0c;安装。 3.下载完成后双击打开&#xff0…

JavaWeb--纯小白笔记03:servlet入门---动态网页的创建

笔记&#xff1a;index.html在tomcat中为默认的名字&#xff0c;html里面的语法不严谨。改配置文件要小心&#xff0c;不然容易删掉其他 Servlet&#xff1a;服务器端小程序&#xff0c;写动态网页需要用Servlet&#xff0c;普通的java类通过继承HttpServlet&#xff0c;可以响…

c++9月25日

1.栈的实现 头文件 #ifndef STACKHEAD_H #define STACKHEAD_H #include <iostream> #define MAX 30 using namespace std;class Stack { private:int *ptr;int top; public:Stack();Stack(int *,int);~Stack();bool full();bool empty();int push(int);void show();Sta…

一个超强的Python库!HTTP请求性能分析工具推荐:httpstat!

什么是Python httpstat&#xff1f; httpstat是一个基于命令行的工具&#xff0c;用于在终端中展示HTTP请求的详细统计信息。它以可视化和易读的方式显示了HTTP请求的各个阶段的性能数据&#xff0c;如DNS解析、TCP连接、TLS握手、发送请求、服务器处理、接收响应等。 使用ht…

2024.9.26 Spark学习

资料&#xff1a; Spark基础入门-第一章-1.1-Spark简单介绍_哔哩哔哩_bilibili &#xff08;1&#xff09;基础知识 Apache Spark 是用于大规模数据&#xff08;large-scale data&#xff09;处理的统一分析引擎。 分布式处理数据 PySpark模块 Spark 和 Hadoop 有区别&…

QT编译之后的debug包下运行程序双击运行出现无法定位程序输入点__gxx_personlity_seh0于动态链接库

1.出现这个错误的原因是&#xff1a; 缺少如下文件&#xff1a; 2.解决方法&#xff1a; 在运行程序.exe所在的目录执行&#xff1a;windeployqt untitled.exe&#xff08;指打包的运行程序&#xff09; 3.如果执行提示由于找不到qt5core.dll,无法继续执行代码和无法识别win…

c++进阶学习-----继承

1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈现了面向对象 程序设计的…

聚合函数count 和 group by

count函数&#xff1a; count&#xff08;列名&#xff09; SELECT COUNT(sid) FROM grade 统计列中所有的数值个数&#xff0c;会忽略null值。 count&#xff08;*&#xff09;和count&#xff08;1&#xff09; SELECT COUNT(*) FROM grade SELECT COUNT(1) FROM grade 统…

前端接口报错302 [已解决]

前端接口报错302 [已解决] 在前端开发中&#xff0c;与后端接口的交互是项目成功的关键。然而&#xff0c;遇到如302这样的状态码报错时&#xff0c;可能会让开发者感到困惑。本文将通过详细解析和多个代码案例&#xff0c;帮助你深入理解前端接口报错302&#xff0c;并提供有效…

Redis入门介绍

1.初识Redis 计算机领域的任何问题都可以通过增加一个间接的中间层来解决 1.Redis介绍 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的&#xff0c;使用C语言编写、支持网络调用、基于内存亦可持久化的Key-Value数据库&…

静电势能(electrostatic potential energy)和电势(electric potential)

静电势能(electrostatic potential energy) 静电势能是把一个电荷从无穷远处移动到这个位置需要做的功。 静电势能的符号&#xff1a; U 图示&#xff1a; 计算公式&#xff1a; U q 1 q 2 4 π ϵ 0 R U \frac{q_1q_2}{4\pi\epsilon_0R} U4πϵ0​Rq1​q2​​ 其中 U …

【JavaEE】——阻塞队列,生产消费者模型(较难)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯&#xff0c;你们的点赞收藏是我前进最大的动力&#xff01;&#xff01;希望本文内容能够帮助到你&#xff01; 目录 一&#xff1a;阻塞队列 1&#xff1a;概念 2&#xff1a;阻塞队列与普通队列比较 二&#xff1a;“生…

简单好用的PDF编辑器有哪些?这4款千万不要错过。

PDF文件在生活中被我们大量使用&#xff0c;所以编辑PDF文件也是常有的事。平时我们用的文档编辑器不一定能够编辑PDF。这个时候就需要使用专业的PDF 编辑器&#xff0c;下面这几款工具就可以帮助我们直接对 PDF 文件中的内容进行编辑&#xff0c;可以有效的提高工作效率。 1、…

测序技术--组蛋白甲基化修饰、DNA亲和纯化测序,教授(优青)团队指导:从实验设计、结果分析到SCI论文辅助

组蛋白甲基化修饰工具(H3K4me3 ChIP-seq)组蛋白甲基化类型也有很多种&#xff0c;包括赖氨酸甲基化位点H3K4、H3K9、H3K27、H3K36、H3K79和H4K20等。组蛋白H3第4位赖氨酸的甲基化修饰(H3K4)在进化上高度保守&#xff0c;是被研究最多的组蛋白修饰之一。 DNA亲和纯化测序 DNA亲…

JPA+Thymeleaf

创建项目:创建一个crm项目 添加依赖: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http:/…

C++ | Leetcode C++题解之第420题强密码检验器

题目&#xff1a; 题解&#xff1a; class Solution { public:int strongPasswordChecker(string password) {int n password.size();bool has_lower false, has_upper false, has_digit false;for (char ch: password) {if (islower(ch)) {has_lower true;}else if (isu…

优化算法(五)—梯度下降算法(附MATLAB程序)

梯度下降算法&#xff08;Gradient Descent&#xff09;是一种常用的优化算法&#xff0c;用于寻找函数的局部最小值。它通过沿着函数梯度的反方向迭代地调整变量&#xff0c;以逐步找到最优解。梯度下降广泛应用于机器学习和深度学习中&#xff0c;特别是在训练模型时优化损失…