C系统编程:一篇文章带你彻底搞懂IO多路复用以及select函数

背景

关于IO多路复用,可谓真是让人又爱又恨,爱的是他没有多线程那般的繁琐却能解决类似多线程的问题,恨的是初学时很难理解。
我看过网上很多人写过select函数的教程,但看过一遍之后大多都是走马观花,总是觉得少了什么。缺少了一点“烟火气”。

下面的这些内容是我经过自己的思考后得到的一些心得,随说没有那么多的专业名词,但我觉得绝对是相当“接地气”,如有错误指出还恳请斧正

IO多路复用

IO多路复用是干啥的?在搞懂这个问题之前我们先搞懂另外一个问题:阻塞的本质是什么?

阻塞的本质

现在想象你在下饭馆,由于服务员需要一定的时间上菜,在没有上菜的这段时间,你不能吃任何东西,这就是阻塞。那么这种情况该如何放到计算机中进行解释呢?
很简单,你将进食的行为看作是CPU工作的行为就可以了。
也就是说,当我们要的数据暂时没有的时候,会进入一种“等待”状态,CPU会进入一种“空转”的状态。
当一个进程或线程等待某个条件(通常是某种资源)满足时,它会进入阻塞状态。在阻塞状态下,进程或线程不能继续执行,直到其等待的条件得到满足。

导致阻塞的情况

常见的导致阻塞的情况有下面三种:

  • 等待I/O操作完成:例如,一个进程读取磁盘文件或从网络接收数据,这些操作通常需要一段时间才能完成,进程在等待这些操作完成时会被阻塞。
  • 等待获取锁:例如,多个进程或线程竞争同一资源时,可能需要使用锁来同步,一个进程在等待获取锁时会被阻塞。
  • 等待进程间通信:例如,一个进程在等待另一个进程发送消息或信号时会被阻塞。

当然,上面这三点中,只有第一条是我们这篇文章讨论的重点。

什么是IO多路复用

正常情况下,我们的一个进程,只能支持一个文件的IO操作,例如:
scanf,这个函数大家都不陌生,它将数据从stdin中读出,然后放进一个空间里面。而stdin的本质是一个文件,对应着系统中的文件描述符号1

不管怎么说,它的本质就是在进行一个读文件的操作,对吧?

那IO多路复用是怎么回事儿呢?

还是拿下饭馆这件事来说,如果你是一个人去吃饭,那么等着上菜的时间自然是可以什么都不做的,但是如果你和朋友一起去吃饭,在上菜之前,你可以在等待的过程中和朋友聊天。在等待的过程中,可以做别的事情。
将这件事反映到CPU上之后,就可以看成,CPU跳出了“空转”的状态,执行别的事情。

实现原理

这件事情该怎么实现呢?
我们知道,不管是read还是write,他们都是依靠缓冲区来操作的。

  • 对于读操作来说,当缓冲区中没有数据时会进入“阻塞状态”
  • 对于写操作来说,当缓冲区中有数据时(说明还未被读出来),会进入“阻塞状态”

基于缓冲区阻塞的原理,我们思考以下过程:

是否可以让CPU跳出空装状态,去执行别的事情。例如,当我们要读数据时,我们不让CPU等待数据,而是定期检查缓冲区中是否存在数据可读,当有数据可读时,再读入,执行后续操作。

上述操作就是IO多路复用的原理

select函数的使用方式

在内核中,维护了一张表:文件描述符表大概长成这样:
他的实现结构是顺序表
内核中的文件描述符表
在内核外,存在这样一种集合:
fd_set
我们称这个结构叫做fd_set,本质上是一种顺序表。
select是怎么实现上面的原理的呢?就是通过构建这两个表的联系
fd_set中,每一个编号都与内核中的文件描述符表一一对应,当你在fd_set中将对应编号位置的数字改为1的时候,通过执行select会将fd_set这个表拷贝到文件描述符表中,如下:
内核中的拷贝
紧接着,内核会逐一检查文件描述符表,通过这个操作,去检查每个文件描述符对应的缓冲区(read write),如果存在可读或者是可写的文件(根据缓冲区类型而定)则返回到fd_set中对应编号的标记。检查一遍之后,fd_set中的内容会被彻底改变,也就是说,传入参数现在变成了返回参数。
在这个返回的fd_set结构中,仍然被标记为1的位置编号所对应的文件描述符号就是可以读或者写的文件。此时,对他们进行读写操作一定不会被“阻塞”

总结一下,select函数的作用就是监视一堆文件是否被可读或可写(当然,还有异常),返回可读以及可写文件的个数。

当然select的最后一个参数是一个时间。这个时间的作用是用于规定监视时间的,具体规则如下,如果在时间之内,有文件描述符的变化则立即返回,如果规定时间内没有并超时,则返回0,当然你也可以设置为NULL,这样,select就会一直监视,直到出现变化为止。

如果文章中有错误或存在疑问,欢迎指出和提问~~~
作者一个工作日之内必定回复!

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若亦_Royi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值