利用select/poll监听多个设备详解

如果一个应用程序去处理多个设备,例如应用程序读取网路数据,按键,串口,一般能想到的有三种方法:

方法1:
串行+阻塞的方式读取:
while(1) {
read(标准输入);
read(网络);
}
缺点:每当阻塞读取标准输入时,如果用户不进行标准输入的操作,而此时客户端给服务器发送数据,导致服务器无法读取客户端发送来的数据!

方法2:
采用多线程或者多进程机制来实现读取:
开辟多个线程,每一个线程处理一个设备,不会导致的数据的无法读取,但是系统的开销相比方法1要大!

方案3:采用linux系统提供的高级IO的处理机制
select/poll:两者一样,主进程能够利用select或者poll能够对多个设备进行监听!

其原理好像:方法1相当于有一个保安,看十户房子,如果小偷进来从第十户开始偷,保安却从第一户挨个检查,没有小偷确还在第一家等着。
方法2相当于雇了十个保安,开销大
方法3相当于买了10套监控设备,一个保安看监控录像,有情况报警


select函数原型:
int select(int nfds,
fd_set readfds,
fd_set
writefds,
fd_set exceptfds,
struct timeval
timeout);
函数功能:
主进程利用此函数能够对多个设备进行监听,一旦发现监听的设备都不可用(不可读、也不可写、也没有异常),那么主进程进入休眠状态,一旦监听的设备中,只要有一个设备可用(可读或者可写或者有异常)都会唤醒休眠的主进程,select也就会返回。

注意这个函数仅仅起到一个监听的功能,数据的后续处理,例如读写都是通过read,write,ioctl来进行!

参数说明:
nfds:
对设备的访问永远先open获取fd;
监听的设备中,最大的文件描述符fd+1;
数据类型fd_set:文件描述符集合,用来保存描述监听的设备,里面存放是被监听设备的文件描述符;如果select要监听某一个设备,必须把这个设备的fd添加到对应的文件描述符集合中!

readfds:读文件描述符集合指针,如果select要监听设备是否可读,需将设备的fd添加到这个集合中!

writefds:写文件描述符集合指针,如果select要监听设备是否可写,需将设备的fd添加到这个集合中!

exceptfds:异常文件描述符集合指针,如果select要监听设备是否有异常,需将设备的fd添加到这个集合中!

注意:一个设备的fd可以同时添加到三个集合中!

timeout:指定监听的超时时间,如果此参数指定了一个时间,例如5秒钟,select发现设备不可用,主进程进入休眠状态,如果5秒之内设备还不可用,5秒到期,主进程主动唤醒;如果此参数指定为NULL,休眠为永久休眠!

返回值:有三种
如果等于0:表明是超时;
如果小于0:表明系统出错;
如果大于0:表明设备可用(至少是一个设备,或者全部);

文件描述符集合操作的方法:
fd_set rfds; //定义读文件描述符集合

//从集合中解除对fd设备的监听
void FD_CLR(int fd, fd_set *set);

//判断是否是设备fd引起的主进程的唤醒,如果是返回true,否则返回false
int FD_ISSET(int fd, fd_set *set);

//添加一个新的被监听的设备
void FD_SET(int fd, fd_set *set);

//清空文件描述符集合
void FD_ZERO(fd_set *set);

注意:如果要重复监听,需要再次清空集合和添加监听设备!


以上是应用程序层面上的函数调用

其在内核层面上:

在sys_select中做休眠,poll不引起休眠
select系统调用过程:
1.应用程序调用select,首先调用C库的select函数实现;

2.C库的select保存select系统调用号到R7寄存器中,调用SVC(新的
)或者SWI(老的)触发软中断,至此由用户空间陷入内核空间,ARM
的工作模式由用户模式转变为SVC管理模式;

3.跳转到内核准备好的异常向量表的入口地址,根据R7保存的系统调
用号,以它为索引在系统调用表中找到对应的实现函数sys_select

4.sys_select要完成:
1.把被监听的设备对应驱动程序的poll函数挨个调用一遍,
被监听的设备都不可用时,它们的驱动的poll函数都返回0;
2.判断是否是驱动主动唤醒,还是超时唤醒,还是接收到信号唤醒;
3.如果即没有驱动主动唤醒,也没有超时唤醒,没有接收到信号,
sys_select调用poll_schedule_timeout主动让进程进入休眠;
4.假设被监听的设备中,有一个设备可用(可读或者可写或者异常
,硬件通过中断来判断),都会唤醒休眠的主进程;
5.sys_select的poll_schedule_timeout函数返回,不再休眠
6.再次把被监听的设备驱动的poll函数挨个调用一遍,此时可用
的设备对应的驱动poll函数会返回非0;
7.if (ret || time_out || …) //ret = 1,立即返回到用户空
间,返回值为ret值

总结:
1.明确本来应该底层驱动的poll函数利用等待队列机制让进程休眠,
但是等待队列休眠9步骤并不都是驱动的poll来编写,有一部分是有内
核sys_select来实现;

2.驱动poll函数完成如下内容即可:
1.调用poll_wait,将当前进程添加到驱动定义的等待队列头中
2.根据设备是否可用,决定返回0还是非0

利用select/poll监听多个设备详解

3.明确:监听机制,底层poll函数不是必须的,如果要监听设备还可
以使用多线程机制也能够完成监听;但是如果要使用select/poll监
听设备,驱动必须有poll实现!

下图是sys_select的简单实现:

利用select/poll监听多个设备详解

通过对内核代码的分析,真正的休眠实现是在内核中实现的

poll_schedule_timeout函数中的schedule_hrtimeout_range中的schedule_hrtimeout_range_clock函数实现的

并不是在poll函数中实现的

poll(轮询)操作在应用程序中用于同时阻塞在多个文件上,当其中任何一个文件有应用程序所等待的事件(可读、可写、出错等)时,poll返回相应的掩码通知应用程序,使得应用程序知道应该对哪个文件做何种操作。按照我的理解,poll的本质可以这样解释:休眠等待多个指定文件中的任何一个发生特定的事件,并将被该文件唤醒;醒来后轮询所有相关文件(通过再次调用所有文件对应驱动的poll方法),获取所有被监控文件的事件信息返回给应用程序。

从这里就可以看出:

(1)其中等待队列的使用是必不可少的。实际上调用poll的进程将会休眠在多个等待队列(一般所有被监控文件的都有至少一个的等待队列)上,从其中任何一个队列上唤醒该进程,都可能使poll函数返回。

(2)驱动中的poll方法不实现休眠,而是:

  1. i、把当前进程添加到相应的等待队列中(仅在休眠时执行,唤醒时不会执行此功能)。
  2. ii、返回文件当前的状态掩码(告知是否有事件发生,休眠和唤醒都会执行)。

通过对内核源码、 《深入Linux设备驱动程序内核机制》的学习,我对Poll系统调用和内核驱动的poll方法的关系和结构有了整体且深入的了解,基本搞清了poll系统调用的执行脉络。对于poll系统调用的内核原理,请大家先看 《深入Linux设备驱动程序内核机制》那本书写的比较详细了,我不废话了。以后我会把我自己觉得需要注意的地方写出来。这里我把这个关系和数据结构图绘制了出来,请大家指正:

利用select/poll监听多个设备详解

对于等待队列的情况,我用下面一个例子和图来示意一下:

例如有3个进程:

task-1:使用poll检测文件1~3

task-2:使用poll检测文件2~3

task-3:使用poll检测文件3

则等待队列的情况如下:

之后,假设task-2由于文件2或3被唤醒,且task-1/3对此不感兴趣(未设置该掩码),那么等待队列的情况如下:

等待队列入口项的添加和删除主要是由poll_initwait(&table);和poll_freewait(&table);完成。

poll_initwait(&table);完成初始化struct poll_wqueues table的工作,而poll_freewait(&table);负责清理这个结构体。这里需要注意的是等待队列中的wait_queue_t并不是在唤醒函数pollwake从队列中删除的,而是最后由poll_freewait(&table);集中处理的。而唤醒函数和普通的wait_event的唤醒函数有很大不同,请大家对比上面的图和之前我写的
《对Linux系统休眠的理解》

中的图。

Original: https://www.cnblogs.com/jiangzhaowei/p/11727957.html
Author: 江召伟
Title: 利用select/poll监听多个设备详解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/552170/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • wsl 加入右键菜单

    如果系统上安装两个版本wsl ubuntu,默认只有一个在右键菜单里,如果加另外一个1、找到ubuntu位置,复制2、打开注册表windows 与 R,输入regedit并运行,定…

    技术杂谈 2023年6月1日
    0106
  • js中常用的语法

    一、注释 二、输出 输出有三种: 三、变量 概述:变量是在内存中生成一个空间用来存储数据。 1.声明变量 var age; 2.同时声明多个变量,使用逗号隔开。 Original:…

    技术杂谈 2023年5月31日
    0120
  • 上周热点回顾(6.20-6.26)

    热点随笔: · 基于Vite+React构建在线Excel (葡萄城技术团队)· CentOS中实现基于Docker部署BI数据分析 (葡萄城技术团队)· MAUI与Blazor共…

    技术杂谈 2023年5月31日
    0108
  • 前后端分离,SpringBoot如何实现验证码操作

    验证码的功能是防止非法用户恶意去访问登录接口而设置的一个功能,今天我们就来看看在前后端分离的项目中,SpringBoot是如何提供服务的。 SpringBoot版本 本文基于的Sp…

    技术杂谈 2023年6月21日
    0125
  • excel中图表无法编辑的解决办法

    在多人协同办公的情况下,有些表格往往会设置为共享编辑模式,此时会发现sheet页中的的图表却无法编辑或者操作 解决办法: 1、打开【共享工作簿】 2、取消勾选【允许多用户同时编辑,…

    技术杂谈 2023年7月10日
    0344
  • 2021-11-19 ZonedDateTime与字符串互转

    因为经常要使用ZonedDateTime,涉及到与字符串的相互转换一、ZonedDateTime转为字符串 ZonedDateTime now = ZonedDateTime.no…

    技术杂谈 2023年5月30日
    0109
  • image图片

    *image图片的私有属性 属性 说明 isCircle 是否圆图,true表示圆形,默认值false标示方形 url 图片的链接 <image url="…&…

    技术杂谈 2023年6月1日
    085
  • 给王心凌打Call的,原来是神奇的智能湖仓

    图文原创:谭婧(王❤凌老粉) “爷青回” “我们只是老了,并没有死。” 谭老师作为老粉,热烈庆祝”甜心教主”…

    技术杂谈 2023年5月31日
    085
  • 技术管理进阶——你遇到过耍小聪明的同学吗?

    原创不易,求分享、求一键三连 我们常常说贪小便宜吃大亏,这种案例容易伴随一个名词: 小聪明,那么到底什么是小聪明呢,先看一个案例: 在B站时期,有个比较机灵的学弟问我有没有工作推荐…

    技术杂谈 2023年6月1日
    078
  • zabbix脚本获取web status code,异常告警

    个人博客地址 http://www.darkghost.life python代码,需要安装requests库 1 #!/usr/bin/env python 2 #-*-codi…

    技术杂谈 2023年7月25日
    093
  • 你真的懂Python命名吗?

    转载请注明出处❤️ 作者:测试蔡坨坨 原文链接:caituotuo.top/7417a7f0.html 大家好,我是测试蔡坨坨。 今天,我们来聊一下Python命名那些事儿。 名为…

    技术杂谈 2023年7月11日
    089
  • cocos 场景制作流程

    前面的话 本文将详细介绍 cocos 场景制作流程 节点和组件 Cocos Creator 的工作流程是以组件式开发为核心的,组件式架构也称作组件-实体系统,简单的说,就是以组合而…

    技术杂谈 2023年5月30日
    0109
  • MyBatisPlus 入门教程,这篇很赞

    在之前的文章中我们经常使用MybatisPlus进行增删改查,可能有些小伙伴对mybatisplus不是很熟悉,今天特意出了一般入门级的教程,我自己也是一边学习一边写的,有什么地方…

    技术杂谈 2023年6月21日
    0155
  • uWSGI服务实现优雅重启(graceful reload)的方式

    服务端当前使用方式 直接通过svc发送SIGINT/SIGKILL信号 直接触发real_run脚本中的相关信号通知 使用简单 每次重启所有进程(包括master),重启完成为全新…

    技术杂谈 2023年6月21日
    0146
  • chatops

    ChatOps是什么? ChatOps, 简单地说,这是一种方法,允许团队以聊天室的方式来协作和管理其基础结构、代码和数据的许多方面。通过使用聊天机器人和脚本,团队可以执行命令、查…

    技术杂谈 2023年5月31日
    0149
  • 结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state

    一开始学习了一下 Vuex,感觉比较冗余,就自己做了一个轻量级的状态管理。后来又学习了 Pinia,于是参考 Pinia 改进了一下自己的状态管理。 结合 Vuex 和 Pinia…

    技术杂谈 2023年5月31日
    0112
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球