Linux-笔记 高级I/O操作

前言

        I/O(Input/Output,输入/输出)是计算机系统中的一个重要组成部分,它是指计算机与 外部世界之间的信息交流过程。I/O 操作是计算机系统中的一种基本操作,用于向外部设备(如 硬盘、键盘、鼠标、网络等)读取数据或向外部设备写入数据。

        常见的I/O操作方式:

        1)同步 I/O(Synchronous I/O):在进行 I/O 操作时,程序会一直等待操作完成后再 继续执行后面的代码。如果 I/O 操作阻塞,程序会一直等待,直到操作完成或超时。

        2)异步 I/O(Asynchronous I/O):在进行 I/O 操作时,程序会立即返回,而不必等待 操作完成。当操作完成后,操作系统会通知程序。这种方式可以允许程序在等待 I/O 操作完 成的同时执行其他代码。

        3)阻塞 I/O(Blocking I/O):在进行 I/O 操作时,程序会一直等待操作完成后再继续执行后面的代码。如果 I/O 操作阻塞,程序会一直等待,直到操作完成或超时。阻塞 I/O 是 同步 I/O 的一种。

        4)非阻塞 I/O(Non-blocking I/O):在进行 I/O 操作时,程序会立即返回,而不必等待操作完成。如果 I/O 操作无法立即完成,程序也会立即返回,但是会周期性地检查操作是否完成。非阻塞 I/O 是同步 I/O 的一种。

        5)I/O 多路复用(I/O Multiplexing):是一种同时监视多个 I/O 事件的机制,通常使用select、poll、epoll 等系统调用。程序通过这些调用告知操作系统它要监视哪些 I/O 事件,当有 I/O 事件发生时,操作系统通知程序,并返回发生事件的描述符。I/O 多路复用通常是异步 I/O 模型的一部分。

阻塞I/O与非阻塞I/O

        阻塞和非阻塞的主要区别在于程序在进行 I/O 操作时是否会被阻塞。在实际应用中,阻塞 I/O 的使用场景较为有限,因为阻塞 I/O 会导致程序性能下降,会造成资源浪费。非阻塞 I/O 则可以较好地解决这个问题,但需要程序周期性地检查 I/O 操作是否完成,增加了编程难度。

接下来通过几个小实验来区分阻塞I/O与非阻塞I/O的区别。

       1)阻塞I/O读取鼠标的数据,运行后发现不动鼠标就会一直阻塞直到移动鼠标,这就是阻塞I/O的特点。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void) 
{
    char buf[1024];
    int fd, ret;

    fd = open("/dev/input/event2", O_RDONLY);
    if (-1 == fd) {
        perror("open error \r\n");
        exit(-1);
    }

    memset(buf, 0, sizeof(buf));
    ret = read(fd, buf, sizeof(buf));
    if (0 > ret) {
        perror("read error \r\n");
        close(fd);
        exit(-1);
    }

    printf("读到:%d\r\n", ret);

    close(fd);
    exit(0);
}

        2)非阻塞I/O读取鼠标数据,发现运行后立刻结束了程序,并输出了一些错误信息,提示信息为"Resource temporarily unavailable",意思就是说资源暂时不可用;原因在于调用 read()时,如果鼠标并没有移动或者被按下(没有 发生输入事件),是没有数据可读,故而导致失败返回,这就是非阻塞 I/O。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void) 
{
    char buf[1024];
    int fd, ret;

    fd = open("/dev/input/event2", O_RDONLY | O_NONBLOCK);
    if (-1 == fd) {
        perror("open error \r\n");
        exit(-1);
    }

    memset(buf, 0, sizeof(buf));
    ret = read(fd, buf, sizeof(buf));
    if (0 > ret) {
        perror("read error \r\n");
        close(fd);
        exit(-1);
    }

    printf("读到:%d\r\n", ret);

    close(fd);
    exit(0);
}

                

        3)通过非阻塞I/O+轮询读取鼠标数据,可以发现采用非阻塞方式也会停留住,等到移动鼠标才退出程序,这样虽然可行但是会占用很高的CPU使用率。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    char buf[1024];
    int fd, ret;

    fd = open("/dev/input/event2", O_RDONLY | O_NONBLOCK);
    if (-1 == fd)
    {
        perror("open error \r\n");
        exit(-1);
    }

    memset(buf, 0, sizeof(buf));
    for (;;)
    {
        ret = read(fd, buf, sizeof(buf));
        if (0 < ret)
        {
            printf("成功读取<%d>个字节数据\n", ret);
            close(fd);
            exit(0);
        }
    }
    printf("读到:%d\r\n", ret);

    close(fd);
    exit(0);
}

        4)通过对比发现阻塞式 I/O 的优点在于能够提升 CPU 的处理效率,当自身条件不满足时,进入阻塞状态,交出 CPU 资源,将 CPU 资源让给别人使用;而非阻塞式则是抓紧利用 CPU 资源,譬如不断地去轮训,这样就会导致 该程序占用了非常高的 CPU 使用率!

        但是阻塞I/O也有缺点,我们都知道使用阻塞I/O会在没获取到鼠标移动数据的时候会阻塞,那么如果我在读取鼠标数据之后还有很多任务呢,那我一直不移动鼠标后面的任务就不用完成了吗,肯定不是。虽然我们可以通过创建多个线程去解决这个问题,但是也可以尝试其他办法,比如使用fcntl函数。

        5)使用fcntl函数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud - 开发环境搭建

1、JDK环境安装 1、下载jdk17&#xff1a;下载地址&#xff0c;在下图中红色框部分进行下载 2、双击安装&#xff0c;基本都是下一步直到完成。 3、设置系统环境变量&#xff1a;参考 4、设置JAVA_HOME环境变量 5、在PATH中添加%JAVA_HOME%/bin 6、在命令行中执行&#xff1a;j…

Python学习笔记17:进阶篇(六)代码测试

代码测试 代码测试是软件开发过程中的关键环节&#xff0c;旨在确保代码质量、功能正确性以及性能符合预期。 在开发过程中&#xff0c;进行代码测试有很多好处&#xff1a; 提高软件质量&#xff1a;通过发现并修复错误&#xff0c;测试有助于提升软件的功能性、可靠性和稳…

黑马程序员-瑞吉外卖-前六章

黑马程序员瑞吉外卖 文章目录 1、开发环境搭建1.1 数据库环境1.2 maven项目搭建1.2.1 新建项目1.2.2 整合MyBatisPlus1.2.3 整合Druid1.2.4 配置文件application.yml1.2.5 尝试启动项目1.2.6 将前端静态页面引入到项目中 2、 后台系统登录功能2.1 需求分析2.2 代码开发2.2.1 创…

解析网页数据并且处理网页正则表达式与re模块

目录 一、解析网页数据的技术 1&#xff0e;正则表达式 2&#xff0e;XPath 3&#xff0e;Beautiful Soup 4&#xff0e;JSONPath 二、正则表达式的语法 1&#xff0e;元字符 2&#xff0e;预定义字符集 三、 re 模块的使用 1&#xff0e;创建 Pattern 对象 2&#…

libreoffice报: error while loading shared libraries: libcups.so.2: cannot

切换到cd /opt/libreoffice7.1/programlibreoffice查看版本的时候报:/opt/libreoffice7.1/program/soffice.bin: error while loading shared libraries: libcups.so.2: cannot open shared object file: No such file or directory ./soffice --version解决办法&#xff1a; …

MySQL之复制(六)

复制 复制拓扑 拥有备库的主-主结构 另外一种相关的配置是为每个主库增加一个备库&#xff0c;如图所示。这种配置的优点是增加了冗余&#xff0c;对于不同地理位置的复制拓扑&#xff0c;能够消除站点单点失效的问题。你也可以像平常一样&#xff0c;将读查询分配到备库上。…

深入JVM:详解JIT即时编译器

文章目录 深入JVM&#xff1a;详解JIT即时编译器一、序言二、基础概念1、何为JIT即时编译2、热点代码 三、HotSpot内置的即时编译器1、C1编译器2、C2编译器3、分层编译3.1 协作流程 四、常见JIT优化技术1、方法内联2、逃逸分析&#xff08;1&#xff09;同步锁消除&#xff08;…

从零开始学习Linux(10)----动静态库

目录 1.制作静态库 1.编写源代码 2.编译 3.打包库 4.使用库 2.制作动态库 1.编译 2.打包库 3.总结 3.理解动态库加载 1.站在系统角度理解 2.谈谈编址&#xff0c;可执行程序 1.制作静态库 1.编写源代码 假设你编写了两个源代码文件mymath.c和myprintf.c以及它们对应…

vuex的actions返回结果类型是promise及actions方法互相调用

this.$store.dispatch(‘logout’)返回的结果是Promise类型的 调用成功的情况下&#xff0c;返回状态为fulfilled&#xff0c;值为undefined。 所以可以直接进行.then操作&#xff1a; this.$store.dispatch(logout).then((result) > {console.log(result); });因为 Vuex …

正则表达式;grep、sed、awk、soft、uniq、tr 详解

正则表达式 概念 正则表达式&#xff08;Regular Expression&#xff0c;常简写为regex、regexp或RE&#xff09;是一种强大的文本处理工具&#xff0c;它使用一种特殊的字符序列来帮助用户检查一个字符串是否与某种模式匹配。 标准正则表达式 首先安装正则表达式pcre库 创…

草莓不是莓,西瓜才是莓——解读 Kubernetes 中被驱逐的 Pod

每天都有成千上万的 Pod 从节点中被驱逐。它们无家可归、困惑不已&#xff0c;不得不放弃之前的生活方式。其中一些甚至变成无节点状态。 在 Kubernetes 中 Pod 被驱逐意味着什么&#xff1f;我们常常能看到 Pod 因为资源不足被终止。但为什么会发生这种情况呢&#xff1f; 驱…

ChatGPT API技术教程OpenAI APIKey在线对接-Chat Completion对象

表示模型根据提供的输入返回的聊天完成响应。 {"id": "chatcmpl-123","object": "chat.completion","created": 1677652288,"model": "gpt-3.5-turbo-0125","system_fingerprint": "fp…

ElementUI组件库,分页组件靠右显示

ElementUI组件库&#xff0c;分页组件靠右显示 分页组件 &#xff0c;el-pagination组件默认靠左显示&#xff0c;靠右显示的话只需给layout添加一个“->”属性值即可, 看图

AMEYA360代理品牌江苏润石:RS8661/2/4系列高压精密低噪声运算放大器

继RS8651/2/4系列高压精密低噪声运算放大器成功推向市场&#xff0c;润石科技再次成功量产RS8661/2/4系列高压精密低噪声运算放大器。 RS8661/2/4系列产品将工作电压提升到最高36V(18V)、失调电压进一步优化到5μV、在工业现场数据采集、各种仪器仪表测量设备\分析设备上有着广…

IDEA services模块无法启动springboot服务(添加了springboot但是为空白)

https://blog.csdn.net/m0_54042402/article/details/117918995 https://blog.csdn.net/qq_46550964/article/details/122235235 Alt8 显示services模块 发现有springboot启动模块&#xff0c;点一下springboot之后&#xff0c;这个模块就消失了 会自动在.idea文件夹下的work…

选专业填志愿,家庭经济条件是必须考虑因素

对比过去&#xff0c;大部分家庭的物质条件已经好很多了&#xff0c;但也有一部分家庭条件较为困难&#xff0c;对于家庭条件较为困难的高考学生而言&#xff0c;高考志愿填报需要考虑的因素更多&#xff0c;因为自己就读的专业&#xff0c;绝对不能是自己的家庭无法负担的专业…

数值分析笔记(三)函数逼近

最佳平方逼近 函数逼近是使用一种简单易算的函数来近似表示一个复杂函数。 该问题可转化为求解线性方程组 G n C F n ​ G_{n}CF_{n}​ Gn​CFn​​ 其中&#xff0c;系数 C ( c 0 , c 1 , ⋯ , c n ) T , F n ( ( f , φ 0 ) , ( f , φ 1 ) , ⋯ , ( f , φ n ) ) T C(c…

Java网络编程之UDP通信与TCP通信交互代码实现

​import java.net.InetAddress; import java.io.IOException; class Main {public static void main(String[] args) {try { InetAddress localAddress InetAddress.getLocalHost(); //获得本地主机 InetAddress remoteAddress InetAddress.getByName("www.itcast.cn&qu…

非强化学习的对齐方法

在文章《LLM对齐“3H原则”》和《深入理解RLHF技术》中&#xff0c;我们介绍了大语言模型与人类对齐的“3H原则”&#xff0c;以及基于人类反馈的强化学习方法&#xff08;RLHF&#xff09;&#xff0c;本文将继续介绍另外一种非强化学习的对齐方法&#xff1a;直接偏好优化&am…

【Java】解决Java报错:IllegalMonitorStateException in Synchronization

文章目录 引言一、IllegalMonitorStateException的定义与概述1. 什么是IllegalMonitorStateException&#xff1f;2. IllegalMonitorStateException的常见触发场景3. 示例代码 二、解决方案1. 确保在同步代码块或方法中调用wait()、notify()和notifyAll()2. 使用同步方法3. 使用…