Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >嵌入式Linux:阻塞式I/O与非阻塞式I/O

嵌入式Linux:阻塞式I/O与非阻塞式I/O

作者头像
不脱发的程序猿
发布于 2025-03-10 10:58:53
发布于 2025-03-10 10:58:53
30900
代码可运行
举报
运行总次数:0
代码可运行

Linux系统中,I/O操作可以分为两种模式:阻塞式I/O和非阻塞式I/O。

这两种模式决定了进程在执行I/O操作时的行为方式,以及CPU资源的利用效率。

阻塞的本质是进程在无法完成某个操作时,进入休眠状态,交出了CPU控制权,等待操作条件满足再被唤醒执行。

这种情况下,进程会被挂起,暂停执行其他任务。

例如,像wait()、pause()、sleep()等函数都会导致进程进入阻塞状态。

非阻塞则是指即使操作条件尚未满足,进程也不会等待,而是立刻返回控制权并继续执行其他任务。

1

阻塞式 I/O (Blocking I/O)

阻塞式I/O是默认的I/O操作模式。它的典型特点是,当对文件或设备进行读写操作时,如果资源当前不可用,操作系统会挂起调用者,直到资源变得可用。

例如:

  • 对于普通文件(如文本文件),即使读写的数据量较大,read()或write()总会在有限时间内返回。这是因为普通文件的I/O操作不会阻塞。
  • 对于特殊类型的文件,如管道文件、网络套接字和字符设备文件,如果在读取数据时文件无数据可读,进程会被阻塞,直到有数据可用时才被唤醒。这种行为能够提升系统的响应效率,因为当条件不满足时,进程进入阻塞状态,CPU资源可以被其他进程利用。

2

非阻塞式 I/O (Non-blocking I/O)

非阻塞I/O则是在执行I/O操作时,不管资源是否可用,操作系统都不会让进程进入阻塞状态,而是立即返回控制权。

通常返回一个特殊的错误码(如EAGAIN),表示当前操作未能完成,资源暂时不可用。

非阻塞I/O一般需要轮询资源状态或使用异步事件通知来检测资源是否变得可用。

3

阻塞与非阻塞 I/O 的区别

举个例子,假设程序尝试从管道文件或网络套接字中读取数据:

  • 阻塞式 I/O:如果当前没有数据可读,调用read()函数时,进程会被挂起,直到有数据写入管道或网络缓冲区为止。这段时间,CPU可以分配给其他进程使用。
  • 非阻塞式 I/O:即使没有数据可读,read()函数也会立即返回,并设置errno为EAGAIN或EWOULDBLOCK。进程可以选择继续执行其他任务,或者通过轮询方式不断尝试读取,直到数据可用。

4

阻塞与非阻塞 I/O 的优缺点

阻塞式 I/O 优点

  • 程序结构简单,不需要处理I/O状态的变化。
  • 在I/O等待时,能够让出CPU资源,提高系统整体的CPU利用效率。

阻塞式 I/O 缺点

  • 由于进程可能长时间阻塞,会降低系统的响应性。
  • 不适合高并发场景,因为每个阻塞的进程都会占用一个线程或进程资源。

非阻塞式 I/O 优点

  • 提高响应性,特别适用于需要实时交互的场景。
  • 适合高并发服务器程序,如网络服务器,使用非阻塞I/O可以高效处理大量请求。

非阻塞式 I/O 缺点:程序复杂度增加,需要管理I/O状态和轮询操作。

如果没有采用合适的等待机制(如select、poll或epoll),可能会导致CPU资源被占用过多。

以鼠标输入设备文件为例,Linux中鼠标对应的设备文件通常位于/dev/input/目录下,命名为mouseX(X为序号)或eventX。

例如,使用od命令查看/dev/input/event3设备的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo od -x /dev/input/event3

在终端中移动鼠标或点击按钮时,会输出相应的数据。

如果没有输出,说明该设备文件不是鼠标对应的设备。

编写一个测试程序,使用阻塞式I/O读取鼠标的输入:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main() {
    int fd = open("/dev/input/event3", O_RDONLY);
    if (fd == -1) {
        perror("Error opening device");
        return 1;
    }
    char buffer[128];
    printf("Reading from mouse device...\n");
    while (1) {
        // 阻塞等待,直到有数据可读
        int bytes_read = read(fd, buffer, sizeof(buffer));
        if (bytes_read > 0) {
            printf("Read %d bytes from the mouse\n", bytes_read);
        }
    }
    close(fd);
    return 0;
}

在这个程序中,如果鼠标没有输入数据,read()函数会阻塞,进程进入休眠状态,直到检测到鼠标动作才继续执行。

修改程序,使其以非阻塞方式读取鼠标设备数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main() {
    int fd = open("/dev/input/event3", O_RDONLY | O_NONBLOCK);
    if (fd == -1) {
        perror("Error opening device");
        return 1;
    }
    char buffer[128];
    printf("Reading from mouse device (non-blocking)...\n");
    while (1) {
        int bytes_read = read(fd, buffer, sizeof(buffer));
        if (bytes_read > 0) {
            printf("Read %d bytes from the mouse\n", bytes_read);
        } else if (bytes_read == -1 && errno == EAGAIN) {
            // 没有数据可读,非阻塞操作立刻返回
            printf("No data available, will try again...\n");
        }
        // 稍微休眠一下,避免CPU资源过度消耗
        usleep(100000);
    }
    close(fd);
    return 0;
}

在这个程序中,即使没有鼠标数据,read()也会立即返回,并设置errno为EAGAIN。

此时程序不会被挂起,而是可以继续尝试读取或执行其他任务。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 美男子玩编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
I/O的内核原理与5种I/O模型
我们都知道unix世界里、一切皆文件、而文件是什么呢?文件就是一串二进制流而已、不管socket、还是FIFO、管道、终端、对我们来说、一切都是文件、一切都是流、在信息交换的过程中、我们都是对这些流进行数据的收发操作、简称为I/O操作(input and output)、往流中读出数据、系统调用read、写入数据、系统调用write、不过话说回来了、计算机里有这么多的流、我怎么知道要操作哪个流呢?做到这个的就是文件描述符、即通常所说的fd(file descriptor)、一个fd就是一个整数、所以对这个整数的操作、就是对这个文件(流)的操作、我们创建一个socket、通过系统调用会返回一个文件描述符、那么剩下对socket的操作就会转化为对这个描述符的操作、不能不说这又是一种分层和抽象的思想、
小柒吃地瓜
2020/04/21
2.2K0
I/O的内核原理与5种I/O模型
【嵌入式】基于ARM的嵌入式Linux开发总结
2、嵌入式硬件系统的结构 (1)嵌入式处理器+外围硬件 (2)常见的外围硬件:电源、时钟、内存、I/O、通信、调试; 3、嵌入式处理器 (1)ARM、S3C6410、STM32单片机、华为海思、高通骁龙等 (2)Intel /AMD 都不是嵌入式处理器 4、嵌入式操作系统 功能: 种类:嵌入式linux;WinCE;Vxworks;μC/OS-II;Android;IOS。注意:linux不是嵌入式操作系统;MAC OS WINDOWS XP/7/8/10都不是
全栈程序员站长
2022/06/28
19.2K0
【嵌入式】基于ARM的嵌入式Linux开发总结
socket阻塞与非阻塞,同步与异步、I/O模型
在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:
用户6280468
2022/03/21
3.6K0
socket阻塞与非阻塞,同步与异步、I/O模型
高级IO之非阻塞IO和阻塞IO
非阻塞 I/O(Input/Output)是一种在进行文件和套接字操作时不阻塞进程的机制。在 Linux 中,非阻塞 I/O 可以通过设置文件描述符(File Descriptor)为非阻塞模式来实现。
Linux兵工厂
2024/02/27
3620
高级IO之非阻塞IO和阻塞IO
浅谈I/O多路复用
​作为程序员,在日常工作中,都或多或少的接触过网络I/O这个概念,接触过网络编程,听说过socket等等,但是对于更深层次的理解,多少还是有点欠缺,通过本文,可以了解网络中最重要的模块I/O,以及对几种网络模型的介绍,在我们日常工作开发过程中,可以针对特定需求,选择特定的网络模型,达到事半功倍的效果。
高性能架构探索
2021/03/26
9490
嵌入式Linux:异步I/O
与I/O多路复用机制(如select和poll)相比,异步I/O通过信号通知机制,使得进程不需要反复查询I/O状态,而是由内核主动向进程发送信号(如SIGIO)来通知I/O状态的变化。
不脱发的程序猿
2025/03/29
3490
嵌入式Linux:异步I/O
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
http://blog.csdn.net/hguisu/article/details/38638183(牛逼100多名)
bear_fish
2018/09/20
2.2K0
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
高性能网络编程 - 解读5种I/O模型
以上两个关键点最终都与操作系统的 I/O 模型以及线程(进程)模型相关,我们先详细看一下I/O模型 。
小小工匠
2023/11/11
3810
高性能网络编程 - 解读5种I/O模型
嵌入式Linux:文件I/O和标准I/O库
文件 I/O (Input/Output)和标准 I/O 库是用于在 C 语言中进行文件操作的两种不同的方法。
不脱发的程序猿
2024/05/26
2660
【Linux】从零开始认识五种IO模型 --- 理解五种IO模型,开始使用非阻塞IO
通过网络通信的学习,我们能够理解网络通信的本质是进程间通信,而进程间通信的本质就是IO。
叫我龙翔
2024/11/02
1140
【Linux】从零开始认识五种IO模型 --- 理解五种IO模型,开始使用非阻塞IO
嵌入式Linux:I/O多路复用
Linux中的I/O多路复用是指一种同时监控多个文件描述符的机制,允许程序在不阻塞的情况下等待多个I/O事件。
不脱发的程序猿
2025/04/19
1090
嵌入式Linux:I/O多路复用
socket阻塞与非阻塞,同步与异步、I/O模型
在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:
黄规速
2022/04/14
3.2K0
socket阻塞与非阻塞,同步与异步、I/O模型
socket阻塞与非阻塞,同步与异步I/O模型
作者:huangguisu 原文出处:http://blog.csdn.net/hguisu/article/details/7453390
bear_fish
2018/09/20
3.6K0
socket阻塞与非阻塞,同步与异步I/O模型
在 C/C++ 异步 I/O 中使用 MariaDB 的非阻塞接口
对 C/C++,MySQL 提供的库传统上都是阻塞操作,因此适合多线程 / 进程服务器架构编程。但是如果用 C/C++ 编写服务器,往往对性能会有极致要求,此时采用非阻塞的异步 I/O 才是更好的框架。
amc
2018/09/12
3.5K0
在 C/C++ 异步 I/O 中使用 MariaDB 的非阻塞接口
Linux编程(阻塞和非阻塞IO)
Linux设备驱动中的阻塞和非阻塞I/0,简单来说就是对I/O操作的两种不同的方式,驱动程序可以灵活的支持用户空间对设备的这两种访问方式。
用户2617681
2019/08/08
5.8K0
【专业技术】Linux设备驱动第七篇:高级字符驱动操作之阻塞IO
我们之前介绍过简单的read,write操作,那么会有一个问题:当驱动无法立即响应请求该怎么办?比如一个进程调用read读取数据,当没有数据可读时该怎么办,是立即返回还是等到有数据的时候;另一种情况是进程调用write向设备写数据,如果缓冲区满了或者设备正忙的时候怎么办,是立即返回还是继续等待直到设备可写?这种情况下,一般的缺省做法是使进程睡眠直到请求可以满足为止。本篇就介绍遇到这类问题驱动的处理方法。 睡眠 什么是睡眠?一个进程睡眠意味着它暂时放弃了CPU的运行权,直到某个条件发生后才可再次被系统调度。
程序员互动联盟
2018/03/13
1.5K0
【i.MX6ULL】驱动开发10——阻塞&非阻塞式按键读取
上篇文章:【i.MX6ULL】驱动开发9——Linux IO模型分析,介绍了linux中的五种I/O模型,本篇,就来使用阻塞式I/O和非用阻塞式I/O两种方式进行按键的读取实验,并对比之前使用输入捕获和中断法检测的按键程序,查看CPU的使用率是否降低。
xxpcb
2021/12/09
6210
【i.MX6ULL】驱动开发10——阻塞&非阻塞式按键读取
I/O 多路复用, select, poll, epoll
I/O 是应用程序必然逃不掉的一个话题。大家在计算机基础学习中,学过计组,操作系统和计网,而想要把 I/O 研究深入肯定要将对这三个计算机基础方面有所深入。
ge3m0r
2024/05/16
1340
Linux之《荒岛余生》(四)I/O篇
我们在cpu篇就提到,iowait高一般代表硬盘到瓶颈了。wait的意思,就是等,就像等正在化妆的女朋友,总是带着一丝焦躁。本篇是《荒岛余生》系列第四篇,I/O篇,计算机中最慢的那一环。其余参见:
xjjdog
2019/09/24
1.3K0
Linux之《荒岛余生》(四)I/O篇
linux网络编程之socket(八):五种I/O模型和select函数简介
s1mba
2017/12/28
2.1K0
linux网络编程之socket(八):五种I/O模型和select函数简介
相关推荐
I/O的内核原理与5种I/O模型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验