0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux中如何使用信号驱动式I/O?

FPGA之家 来源:嵌入式Hacker 作者:嵌入式Hacker 2021-03-12 14:47 次阅读

一、Linux 的 5 种 IO 模型

二、如何使用信号驱动式 I/O?

三、内核何时会发送 “IO 就绪” 信号?

四、最简单的示例

五、扩展知识

一、Linux 的 5 种 IO 模型

阻塞式 I/O:

系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止。

afa36cae-82f4-11eb-8b86-12bb97331649.png

点击查看大图

非阻塞式 I/O (O_NONBLOCK):

系统调用则总是立即返回,而不管事件是否已经发生。

afe56582-82f4-11eb-8b86-12bb97331649.png

点击查看大图

I/O 复用 (select、poll、epoll):

通过 I/O 复用函数向内核注册一组事件,内核通过 I/O 复用函数把其中就绪的事件通知给应用程序。

b233d076-82f4-11eb-8b86-12bb97331649.png

点击查看大图

信号驱动式 I/O (SIGIO):

为一个目标文件描述符指定宿主进程,当文件描述符上有事件发生时,SIGIO 的信号处理函数将被触发,然后便可对目标文件描述符执行 I/O 操作。

b285771e-82f4-11eb-8b86-12bb97331649.png

点击查看大图

异步 I/O (POSIX 的 aio_ 系列函数):

异步 I/O 的读写操作总是立即返回,而不论 I/O 是否是阻塞的,真正的读写操作由内核接管。

点击查看大图

思考一下,什么时候应该选择何种 I/O 模型?为何要这么选择?

下面重点关注信号驱动式 I/O 这一模型,其他模型可查阅文末参考书籍。

二、如何使用信号驱动式 I/O?

一般通过如下 6 个步骤来使用信号驱动式 I/O 模型。

1》 为通知信号安装处理函数。

通过 sigaction() 来完成:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

默认情况下,这个通知信号为 SIGIO。

2》 为文件描述符的设置属主。

通过 fcntl() 的 F_SETOWN 操作来完成:

fcntl(fd, F_SETOWN, pid)

属主是当文件描述符上可执行 I/O 时,会接收到通知信号的进程或进程组。

pid 为正整数时,代表了进程 ID 号。

pid 为负整数时,它的绝对值就代表了进程组 ID 号。

3》 使能非阻塞 I/O。

通过 fcntl() 的 F_SETFL 操作来完成:

flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | O_NONBLOCK);

4》 使能信号驱动 I/O。

通过 fcntl() 的 F_SETFL 操作来完成:

flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | O_ASYNC);

5》 进程等待 “IO 就绪” 信号的到来。

当 I/O 操作就绪时,内核会给进程发送一个信号,然后调用在第 1 步中安装好的信号处理函数。

6》 进程尽可能多地执行 I/O 操作。

循环执行 I/O 系统调用直到失败为止,此时错误码为 EAGAIN 或 EWOULDBLOCK。

原因:

信号驱动 I/O 提供的是边缘触发通知,即只有当 I/O 事件发生时我们才会收到通知,

且当文件描述符收到 I/O 事件通知时,并不知道要处理多少 I/O 数据。

三、内核何时会发送 “IO 就绪” 信号?

对于不同类型的文件描述符,情况不一样。

1》 终端

对于终端,当有新的输入时会会产生信号。

2》 管道和 FIFO

对于读端,下列情况会产生信号:

数据写入到管道中;

管道的写端关闭;

对于写端,下列情况会产生信号:

对管道的读操作增加了管道中的空余空间大小。

管道的读端关闭;

3》 套接字

对于 UDP 套接字,下列情况会产生信号:

数据报到达套接字;

套接字上发生异步错误;

对于 TCP 套接字,信号驱动式 I/O 近乎无用。

太多情况都会产生信号,而我们又无法得知事件类型,因此这里就不再列举其产生信号的情况。

四、最简单的示例

信号处理函数:

static volatile sig_atomic_t gotSigio = 0; static void handler(int sig) { gotSigio = 1; }

主程序:

int main(int argc, char *argv[]) { int flags, j, cnt; struct termios origTermios; char ch; struct sigaction sa; int done; /* Establish handler */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = handler; if (sigaction(SIGIO, &sa, NULL) == -1) { perror(“sigaction() ”); exit(1); } /* Set owner process */ if (fcntl(STDIN_FILENO, F_SETOWN, getpid()) == -1) { perror(“fcntl() / F_SETOWN ”); exit(1); } /* Enable “I/O possible” signaling and make I/O nonblocking */ flags = fcntl(STDIN_FILENO, F_GETFL); if (fcntl(STDIN_FILENO, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1) { perror(“fcntl() / F_SETFL ”); exit(1); } for (done = 0, cnt = 0; !done ; cnt++) { sleep(1); if (gotSigio) { gotSigio = 0; /* Read all available input until error (probably EAGAIN) or EOF */ while (read(STDIN_FILENO, &ch, 1) 》 0 && !done) { printf(“cnt=%d; read %c ”, cnt, ch); done = ch == ‘#’; } } } exit(0); }

运行效果:

。/build/sigio a cnt=0; read a cnt=0; read abc cnt=4; read a cnt=4; read b cnt=4; read c cnt=4; read # cnt=7; read #

该程序会先使能信号驱动 IO,然后循环执行计数操作。

当有 IO 就绪信号到来时,会去终端读取数据并打印出来,然后继续执行计数操作。

五、扩展知识

I/O 多路复用 、信号驱动 I/O 以及 epoll 机制可用于监视多个文件描述符。

它们并不实际执行 I/O 操作,当某个文件描述符处于就绪态,仍需采用传统的 I/O 系统调用来完成 I/O 操作。

相比 I/O 多路复用,当监视大量的文件描述符时信号驱动 I/O 有着显著的性能优势,原因是内核能够帮进程记录了正在监视的文件描述符列表。

信号驱动 I/O 的缺点:

信号的处理流程较为复杂;

无法指定需要监控的事件类型。

Linux 特有的 epoll 是一个更好的选择。

六、相关参考

UNIX 网络编程卷1

6.2 I/O模型

25 信号驱动式I/O

Linux-UNIX 系统编程手册

63 其他备选的I/O模型

Linux 高性能服务器编程

8.3 I/O 模型

Linux 多线程服务端编程_使用muduo C++网络库

原文标题:Linux-C 编程 | 3 分钟快速了解信号驱动式 IO

文章出处:【微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206736
  • 信号
    +关注

    关注

    11

    文章

    2640

    浏览量

    75388

原文标题:Linux-C 编程 | 3 分钟快速了解信号驱动式 IO

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    程序USB的DP和DM IO配置为50Mhz,需要打开I/O补偿单元来减少噪音吗?

    大家好: 数据手册上说:当I/O口速度配置为50MHz或100MHz时,开启I/O补偿单元来减少对电源带来的噪音 那么,我的程序USB的D
    发表于 04-26 06:51

    推荐!单片机I/O的常用驱动与隔离电路

    使用。针对电气控制产品的特点,本文讨论了几种单片机I/O的常用驱动和隔离电路的设计方法,对合理地设计电气控制系统,提高电路的接口能力,增强系统稳定性和抗干扰能力有实际指导意义。 1、 输入电路设计
    发表于 03-12 09:24

    嵌入软件开发应该掌握哪些知识?

    编译和调试的过程还需要用到gcc完成交叉编译,使用gdb完成相关的调试和分析。因此我们还需要掌握gcc和gdb的使用。 2.进阶知识 2.1文件 I/O 文件操作:包括创建、打开、读取、写入和关闭
    发表于 02-19 11:23

    Linux内核中信号详解

    信号和多线程程序 4 与信号相关的数据结构 4.2.1 x86/Linux2.6.11的定义 4.2.2 x86-64/Linux2.6.11的定义 4.2.3 x86-64/
    的头像 发表于 01-13 09:40 762次阅读
    <b class='flag-5'>Linux</b>内核中<b class='flag-5'>信号</b>详解

    扩展模块驱动分布I/O在新能源锂电池自动化生产中的发展

    材料进行切边、折边、点胶等操作,使其对接部分更加严密,不会造成锂电池内部液体的泄露。 分布I/O模块可以采集磁性开关及光电信号并通过输出模块控制电磁阀从而控制气缸动作,来完成电池的
    发表于 12-28 11:20

    linux安装网卡驱动教程

    Linux系统中安装网卡驱动是一个比较基础的操作,下面我将为你详细讲解如何安装网卡驱动。 第一步,检查网卡型号和驱动支持情况:首先,你需要确定你的网卡型号,并查看该网卡型号在
    的头像 发表于 11-17 11:11 1638次阅读

    一文总结linux的platform驱动

    linux设备驱动中,有许多没有特定总线的外设驱动,在实际开发中,又需要使用到总线、驱动和设备模型这三个概念,故而linux提供了plat
    的头像 发表于 10-16 16:45 412次阅读
    一文总结<b class='flag-5'>linux</b>的platform<b class='flag-5'>驱动</b>

    什么是嵌入Linux

    什么是嵌入Linux? 对于很多电气、电信、通信专业的同学来说,对口专业就业方向主要有软、硬件两个方向。无论是对于学生还是就业而言,软硬件的开发学习,嵌入物联网在近年来无疑是一个摆在面前
    发表于 10-11 13:47

    Linux模块相关命令 Linux驱动模块的编写与挂载

    Linux模块相关命令 Linux驱动模块的编写与挂载
    发表于 10-01 12:20 198次阅读
    <b class='flag-5'>Linux</b>模块相关命令 <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>模块的编写与挂载

    嵌入Linux应用开发的完全手册

    嵌入Linux在嵌入领域发展迅速、需求旺盛,但是嵌入Linux 的入门很难。初学者多是自己琢磨,效率不高。学习过程
    发表于 09-25 07:12

    基于树莓派的嵌入Linux开发教学

    树莓派对于全球嵌入 Linux 开发及教育已经并将继续带来广泛的影响,及早将之引入我国主流的嵌入开发与教学环境或将是有益的。尽管传统的 “ARM 开发板硬件设计 +
    发表于 09-21 07:09

    I/ O检测时如何使用SysTick进行计数

    v3.01.001 硬件: NuTiny-EVB-123-LQFP64_V1.0 在正常情况下,当I/O检测到信号时,它可能受到噪音的干扰,而系统反应不正确。此示例使用系统反射器过滤在一定时间间隔内产生的紧张
    发表于 08-30 08:03

    基于Linux使用spidev驱动OLED

    如果不想编写spi设备驱动,那么linux内核提供了一个通用的spidev设备驱动,提供统一的字符设备操作,那么只需要在应用层读写和控制即可。以SPI OLED为例子,使用spidev驱动
    发表于 06-16 10:36 2720次阅读
    基于<b class='flag-5'>Linux</b>使用spidev<b class='flag-5'>驱动</b>OLED

    Linux reset子系统及驱动实例

    上篇讲了Linux clock驱动,今天说说Linux的reset驱动
    发表于 05-31 16:16 610次阅读
    <b class='flag-5'>Linux</b> reset子系统及<b class='flag-5'>驱动</b>实例

    Linux之PWM驱动

    本文主要讲述了Linux的PWM驱动框架、实现方法、驱动添加方法和调试方法。
    发表于 05-25 09:19 408次阅读
    <b class='flag-5'>Linux</b>之PWM<b class='flag-5'>驱动</b>