I/O多路复用——poll

上一篇我们说了关于select的相关信息,我们可以看到select是有弊端的,所以为了解决select的弊端,UNIX又在后期提出了poll。

select的弊端这里就不多说了,上一篇博客有提及。

poll


poll和select类似,不过在一些方面改善了select的弊端。它也是在指定的时间进行轮询文件描述符,查看是否有就绪时间发生。

和上次一样,我们先来看一下poll系统调用。

 int poll(struct pollfd *fds, nfds_t nfds, int timeout);

fds是一个pollfd的结构体数组。

struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };

这就是这个结构体数组每个元素。fd用来记录对应的文件描述符,events用来表示poll所监听的事件,这个由用户来设置。revents用来表示返回的事件。revents是通过内核来进行操作修改。

这里提供了一些合法事件。

事件 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件

后面的三个参数在events无意义,只能作为返回结果存储在revents。

另外,这里需要说的,这些参数如何设置给events,这些宏相当于每一个占用一个比特位,我们可以去想一下位图,所以,如果我们要进行设置两个事件,就使用|操作,另外,当我们去查看事件是否发生的时候,这个时候我们可以使用revents&事件,如果事件发生了,那么结果大于1。这就是一个简单的位运算的,相信你仔细想想就能够理解。

第二个参数nfds,用来监视的文件描述符的数目。

第三个参数是timeout,用来设置超时时间。

参数 说明
-1 poll将永远阻塞,等待知道某个时间发生
0 立即返回
大于0的值 设置正常时间值

返回值
poll返回revents不为0的文件描述符的个数。
失败返回-1

总结


poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。

poll使用了events和revents分流的特点,这样可以使得对关心事件只进行注册一次。

poll基于链表进行存储,没有最大连接数的限制,只取决于内存大小。

poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。poll返回后,需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。

poll的缺点


1、大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样是不是有意义。

2、poll依然需要进行轮询,所消耗的时间太多。

3、水平触发,效率低

示例程序


聊天室程序:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值