Linux——五种IO模型

news2024/12/24 21:20:38

目录

一、I/O的理解

二、五种IO模型

1.阻塞式IO

2.非阻塞式IO

3.信号驱动IO

4.多路复用IO

5.异步IO 


一、I/O的理解

I/O的本质就是输入输出,C语言的stdio,C++的iostream,添加了这两个库,我们才能够进行printf、scanf、cin、cout。

在I/O中,我们大部分时间是在等,比如你调用了scanf(),当前进程就在等待你的输入,你输入完毕后,把输入数据拷贝到内存中,才会继续执行。因此,I/O = 等 + 拷贝。拷贝的效率是硬件决定的,但是等待的时间,是可以由程序来优化的。单位时间内,减少了等的比重,这也就提高了I/O效率。

在网络中,我们经常需要去recv和send,recv是在等待对方发送消息,我来接受,如果此时对方还没有发送消息,我们就会在recv这里阻塞;send则是我发送消息,对方接受消息,当对方的接受缓冲区满了,也会造成阻塞,直到对方接收缓冲区有空间了,才可以发送过去。

如果现在我可以去干自己的事情,等我收到的对方通知(他的条件满足),我们再去调用recv或者send函数,这样就大大提高了效率

二、五种IO模型

为了理解五种IO模型,我们来看个钓鱼的例子,钓鱼 = 等 + 钓 ,这里可以把钓看做是拷贝,钓都是一样的,但是等的过程不相同。

  • 张三:永远看着鱼漂,谁叫他都没有                                                ——阻塞式IO
  • 李四:一会看看鱼漂,一会看看书、刷书视频                                  ——非阻塞轮询式IO
  • 王五:铃铛绑在的鱼竿顶部(铃铛响了,就开始抬杆)                    ——信号驱动式IO
  • 赵六:100个鱼竿一起钓,哪个鱼漂动了就去哪里                            ——多路复用IO
  • 田七:发起了钓鱼,让助手小王去钓鱼,自己去干其他事情             ——异步IO

其中,阻塞、非阻塞、信号驱动、多路复用都是同步IO,他们都参与了IO的过程,要么等了、要么拷贝了、或者都做了。

而田七只是发起了钓鱼,然后就当甩手掌柜,交给小王去等去拷贝,自己并没有参与,他是异步IO。

在这个故事中,河流是操作系统,鱼是数据,鱼漂是数据就绪条件,鱼竿是文件描述符。

1.阻塞式IO

阻塞IO: 在内核将数据准备好之前,系统调用会一直等待。 所有的套接字,默认都是阻塞方式

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

int main()
{
    while (true)
    {
        char buff[1024];
        ssize_t s = read(0, buff, sizeof(buff - 1));
        if(s>0)
        {
            buff[s] = '\0';
            std::cout<<"echo# "<<buff<<std::endl;
        }
        else if (s==0)
        {
            std::cout<<"end stdin"<<std::endl;
            break;
        }
        else
        {
            //TODO
        }
    }
}

2.非阻塞式IO

阻塞IO:如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码。

非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询。这对CPU来说是较大的浪费, 一般只有特定场景下才使用。
 

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstdlib>

//使用F_GETFL将当前的文件描述符的属性取出来(这是一个位图)。
//然后再使用F_SETFL将文件描述符设置回去, 设置回去的同时, 加上一个O_NONBLOCK参数
void SetNoBlock(int fd) 
{             
    // 获取fd文件描述符的状态标志
    int f1 = fcntl(fd, F_GETFL);
    if (f1 < 0)
    {
        std::cerr << "fcntl error" << std::endl;
        exit(0);
    }
    // 设置fd文件描述符的状态标志   f1为老标志的内容,O_NONBLOCK为非阻塞
    fcntl(fd, F_SETFL, f1 | O_NONBLOCK);
}

int main()
{
    SetNonBlock(0);
    while (true)
    {
        char buff[1024];
        ssize_t s = read(0, buff, sizeof(buff) - 1);
        if (s > 0)
        {
            buff[s] = '\0';
            std::cout << "echo# " << buff << std::endl;
        }
        else if (s == 0)
        {
            std::cout << "end stdin" << std::endl;
            break;
        }
        else
        {
            // 非阻塞等待,数据没有准备好,返回值仍然是 -1  但不认为是出错
            // 因此我们需要查看错误码,看具体原因
            if (errno == EWOULDBLOCK || errno == EAGAIN)
            {
                std::cout << "OS的底层数据还没有就绪,errno: " << errno << std::endl;
            }
            else if(errno == EINTR)
            {
                std::cout << "IO 被信号中断,请再次尝试"<< std::endl;
            }
            else
            {
                //这里才是read出错
                break;
            }
        }
        sleep(1);
    }
}

3.信号驱动IO

信号驱动IO:内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作。

4.多路复用IO

IO多路复用:虽然从流程图上看起来和阻塞IO类似。实际上最核心在于IO多路复用能够同时等待多个文件描述符的就绪状态

操作系统给我们提供了select系统调用,我们可以将很多文件描述符交给select管理。多个文件描述符就绪的概率是要比前面IO模式单个文件描述符就绪的概率高得多,当有文件描述符准备就绪,select不进行拷贝,而是通知应用程序,让应用程序去进行相应的IO处理,此时,是不会出现IO阻塞的情况,因为是收到的通知才进行的IO。大大提高了效率。

select的使用 

5.异步IO 

异步IO:由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)。

异步IO,只是发起的IO请求,由操作系统去完成IO等+拷贝的操作,最后吃现成的就行了。 

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

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

相关文章

UDP网口(1)概述

文章目录 1.计算机网络知识在互联网中的应用2.认识FPGA实现UDP网口通信3.FPGA实现UDP网口通信的方案4.FPGA实现UDP网口文章安排5.传送门 1.计算机网络知识在互联网中的应用 以在浏览器中输入淘宝网为例&#xff0c;介绍数据在互联网是如何传输的。我们将要发送的数据包称作A&a…

人工智能AI合集:1、嵌入式LinuxAI开发套件OrangePI AIPRO初体验

前言 随着人工智能技术的飞速发展&#xff0c;AI已经不再是遥不可及的高科技概念&#xff0c;而是逐渐融入到我们的日常生活中。从智能手机的语音助手到家庭中的智能音箱&#xff0c;再到工业自动化和医疗诊断&#xff0c;AI的应用无处不在。然而&#xff0c;要想真正掌握并应用…

数学建模学习(111):改进遗传算法(引入模拟退火、轮盘赌和网格搜索)求解JSP问题

文章目录 一、车间调度问题1.1目前处理方法1.2简单案例 二、基于改进遗传算法求解车间调度2.1车间调度背景介绍2.2遗传算法介绍2.2.1基本流程2.2.2遗传算法的基本操作和公式2.2.3遗传算法的优势2.2.4遗传算法的不足 2.3讲解本文思路及代码2.4算法执行结果&#xff1a; 三、本文…

基于java的设计模式学习

PS &#xff1a;以作者的亲身来看&#xff0c;这东西对于初学者来说有用但不多&#xff0c;这些东西&#xff0c;更像一种经验的总结&#xff0c;在平时开发当中一般是用不到的&#xff0c;因此站在这个角度上用处不大。 1.工厂模式 1.1 简单工厂模式 我们把new 对象逻辑封装…

SpringBoot缓存注解使用

背景 除了 RedisTemplate 外&#xff0c; 自Spring3.1开始&#xff0c;Spring自带了对缓存的支持。我们可以直接使用Spring缓存技术将某些数据放入本机的缓存中&#xff1b;Spring缓存技术也可以搭配其他缓存中间件(如Redis等)进行使用&#xff0c;将某些数据写入到缓存中间件…

【Linux】信号(signal)

目录 一、信号概念&#xff1a; 二、信号的常见状态&#xff1a; 信号递达&#xff1a; 信号未决&#xff1a; 阻塞信号&#xff1a; 忽略信号&#xff1a; 信号在内核中的表示&#xff1a; 三、信号相关函数&#xff1a; sigset_t &#xff08;类型&#xff09;&…

2024.7.19 作业

1.链表的排序 int list_sort(NodePtr L) {if(NULLL || L->len<1){printf("排序失败");return -1;}int lenL->len1;NodePtr p;int i,j;for( i1;i<len;i){for( j0,pL;j<len-i;j,pp->next){if( p->data > p->next->data ){datatype tp-&…

基于51单片机的步进电机控制系统proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1jFlIJ9I5qxjW8sYKd6vrBQ?pwd9d6q 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMic…

阿里开源的音频模型_原理与实操

英文名称: FunAudioLLM: Voice Understanding and Generation Foundation Models for Natural Interaction Between Humans and LLMs 中文名称: FunAudioLLM: 人与LLMs之间自然互动的语音理解和生成基础模型 论文地址: http://arxiv.org/abs/2407.04051v3 相关论文&#xff1a;…

1、springboot3 vue3开发平台-后端-项目构建

文章目录 1. 创建项目1.1 前置环境条件1.2 项目创建 2. 模块配置2.1 父工程配置概述2.2 配置启动模块2.3 父工程相关依赖管理 1. 创建项目 1.1 前置环境条件 idea2023, jdk17 1.2 项目创建 创建父工程并删除不需要的文件目录&#xff1a; 右键父工程依次创建其他模块 最…

Java | Leetcode Java题解之第260题只出现一次的数字III

题目&#xff1a; 题解&#xff1a; class Solution {public int[] singleNumber(int[] nums) {int xorsum 0;for (int num : nums) {xorsum ^ num;}// 防止溢出int lsb (xorsum Integer.MIN_VALUE ? xorsum : xorsum & (-xorsum));int type1 0, type2 0;for (int n…

vue2.0结合使用 el-scrollbar 和 v-for实现一个横向滚动的元素列表,并且能够自动滚动到指定元素(开箱即用)

效果图&#xff1a; 代码&#xff1a; <div class"gas-mode-item-body"><el-scrollbar style"width: 300px;height: 100%;" wrap-style"overflow-y:hidden" ref"scrollbarRef"><div style"display: flex&quo…

python-最小公倍数(PythonTip)

[题目描述] 编写一个程序&#xff0c;找出能被从1到给定数字n&#xff08;包括n&#xff09;的所有数字整除的最小正数(即最小公倍数)。 定义函数smallest_multiple()的函数&#xff0c;参数为n。 在函数内&#xff0c;返回能被从1到给定数字n&#xff08;包括n&#xff09;的…

珈和科技完成全国首个农险服务类数据产品入表,实现数据资产化

近日&#xff0c;珈和科技与东湖大数据合作&#xff0c;完成全国首个保险服务类数据产品入表&#xff0c;标志着我国商业卫星遥感应用领域迈出了数据资产化的关键一步。 此次入表的数据产品为“华北农业保险服务数据集数据产品”&#xff0c;是珈和科技融合卫星遥感与无人机等…

数据结构----栈

前言 Hello&#xff0c;小伙伴们&#xff0c;今天我们继续数据结构的学习&#xff0c;前面我们学习了顺序表和链表的实现&#xff0c;今天的栈知识也是和前面的知识相辅相成。 如果你喜欢我的内容的话&#xff0c;就请不要吝啬自己手中的三连哟&#xff0c;万分感谢&#xff…

# Redis 入门到精通(七)-- redis 删除策略

Redis 入门到精通&#xff08;七&#xff09;-- redis 删除策略 一、redis 删除策略–过期数据的概念 1、Redis 中的数据特征 Redis 是一种内存级数据库&#xff0c;所有数据均存放在内存中&#xff0c;内存中的数据可以通过TTL指令获取其状态。 XX &#xff1a;具有时效性…

Android Studio引入ndk编译的so库, 通过jni给Java程序使用

前言 工作要求将一个C老项目的函数用ndk打包成库给安卓同事的java程序调用。 这个任务我debuff拉满&#xff1a; 自己之前从来没接触过安卓开发&#xff0c;问了老板为什么不让安卓开发来干&#xff0c;老板说安卓开发不懂c&#xff0c;公司就我一个是懂c的。。。项目开发年…

【STM32嵌入式系统设计与开发---拓展】——1_10矩阵按键

这里写目录标题 1、矩阵按键2、代码片段分析 1、矩阵按键 通过将4x4矩阵按键的每一行依次设为低电平&#xff0c;同时保持其它行为高电平&#xff0c;然后读取所有列的电平状态&#xff0c;可以检测到哪个按键被按下。如果某列变为低电平&#xff0c;说明对应行和列的按键被按下…

day2 单机并发缓存

文章目录 1 sync.Mutex2 支持并发读写3 主体结构 Group3.1 回调 Getter3.2 Group 的定义3.3 Group 的 Get 方法 4 测试 本文代码地址&#xff1a; https://gitee.com/lymgoforIT/gee-cache/tree/master/day2-single-node 本文是7天用Go从零实现分布式缓存GeeCache的第二篇。 …

go 实现websocket以及详细设计流程过程,确保通俗易懂

websocket简介&#xff1a; WebSocket 是一种网络传输协议&#xff0c;可在单个 TCP 连接上进行全双工通信&#xff0c;位于 OSI 模型的应用层。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455&#xff0c;后由 RFC 7936 补充规范。 WebSocket 使得客户端和服务器之间的数…