概念篇——IO多路复用的机制

  • Post author:
  • Post category:其他



说明



本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

QQ 群 号:513683159 【相互学习】


内容来源



《Unix环境高级编程》



一、I/O多路复用的引出



不同的I/O使用情形:



情形一:一个输入(写),一个输出(读)

常使用以下形式循环中使用阻塞I/O

while( (n = read(STDIN_FILENO,buf,BUFSIZE)) > 0 )
	if( write(STDOUT_FILENO,buf,n) != n )
		fprintf(stderr,"write error");


情形二:两个输入,两个输出

两个输入中任一个都不能使用阻塞

read()

,因为我们永远不知道哪个输入有我们需要的数据。


方案一




描述





fork()

将一个进程变成两个进程,每个进程处理一条通路(执行阻塞

read()






产生问题

:操作何时终止?


解决问题

:根据不同终止情形进行处理,如:使用信号机制。(使得程序复杂)


方案二




描述



一个进程中的两个线程(执行阻塞I/O)


避免终止的复杂度但要求处理线程之间的同步(使得程序复杂)。


方案三




描述



一个进程中的两个线程(执行非阻塞I/O)



缺点

:浪费CPU时间。(在多任务系统中应该避免使用该方法)


方案四




描述



使用异步I/O技术



基本思想

:进程告诉内核,当一个描述符已准备好可进行I/O时,用一个信号通知它。


存在问题



1.并非所有系统都支持该机制。

2.这种信号对每个进程而言仅有一个起作用。(若两个都起作用则无法分辨)


方案五




描述



使用I/O多路转接技术



基本思想

:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中一个已准备好进行I/O时,该函数才返回,返回时,它告诉进程哪些描述符已准备好可进行I/O。



二、 I/O多路复用概念



1.I/O多路复用是什么?

允许应用在多个文件描述符上同时阻塞,并在其中某个可读写时收到通知。

(一个进程可监视多个文件描述符,若某文件描述符就绪,能通知程序进行相应的读写操作)



2.设计遵循的原则:

①当任何文件描述符指向的文件准备好输入输出时进行通知。

②在一个或更多文件描述符就绪前始终处于睡眠状态

③唤醒

④在不阻塞情况下处理所有I/O就绪的文件描述符

⑤回到①,循环



3.函数种类:

①select()函数

②poll()函数

③epoll()函数



三、函数简介



(1)函数简介:

详细请查看:

函数简介篇——IO多路转接函数:select()/pselect()/poll()/ppoll()


1️⃣

select()/pselect()

——同步I/O多路复用

程序监视多个文件描述符,直到其中一个或多个文件描述符“就绪的”进行某种I/O操作

2️⃣

poll()/ppoll()

——等待文件描述符上的某个事件

等待一组文件描述符中的一个准备好执行I/O



(2)poll()与select()的优缺点



poll()



select()

功能相同,但

poll()

系统调用仍然优于

select()

.




1.

poll()

的优点:





poll()

无需使用者计算最大的文件描述符值加一和传递该参数。



poll()

在应对较大值的文件描述符时更具效率。

想像一下用select() 监视值为900的文件描述符——内核需要检查每个集合中的每个比特位,直到第九百个。



select()

的文件描述符集合是静态大小的,所以要作出权衡:要么集合很小,限制了select()可以监视的文件描述符的最大值,要么较大,但是效率不高。尤其是当不能确定集合的组成是否稀疏时,对较大位掩码的操作效率不高。 使用

poll()

则可以创建合适大小的数组。只需要监视一项或仅仅传递一个结构体。

④若用

select()

,文件描述符集合会在返回时重新创建,这样的话之后每个调用都必须重新初始化它们

。poll()

系统调用分离了输入(

events

字段)和输出(

revents

字段),数组无需改变即而重用。



select()



timeout

参数在返回时是未定义的。可移植的代码需要重新初始化它。然而

pselect()

没有这个问题。



2.

select()

的优点:





poll()

由于某些Unix系统不支持

poll()

,所以


select()

的可移植性更好





select()

提供了更好的超时方案:直到微秒级。

ppoll()



pselect()

在理论上都提供纳秒级的精度,但在实际中,没有任何调用可以可靠的提供哪怕是微秒级的精度。



poll()



select()

更好的是

epoll

接口,一个Linux特有的IO多路复用解决方案,我们将在第四章探讨。



版权声明:本文为weixin_42645653原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。