IO多路复用--select/poll

IO多路复用是一种同步IO模型,在IO操作中,阻塞IO在等待IO操作时如果不满足条件会阻塞挂起,导致一个线程在同一时间只能处理一个IO,而非阻塞方式在进行轮训操作时,当有多个IO需要同时监听时,处理就会很麻烦。IO多路复用同一时间多个不同的IO操作,调用线程在调用时阻塞等待,当有任意监听的IO操作时就会返回。

select模型

采用Reactor模式实现

用户线程 Reactor 内核 注册时间处理器 select 线程轮训 等待数据到达 select 通知用户线程 read请求 数据拷贝 read请求 用户线程 Reactor 内核

select 函数原形
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
其中 nfds是监听的最大描述符
fd_set *readfds, fd_set *writefds,fd_set *exceptfds这三个分别为需要监听读事件、写事件、异常条件对应的描述符集合,对其不敢兴趣可以设置为空。
fd_set定义

typedef struct
{
#ifdef__USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE/__NFDBITS];
#define__FDS_BITS(set)((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE/__NFDBITS];
#define__FDS_BITS(set)((set)->__fds_bits)
#endif
}fd_set;

fd_set其实现采用了位图,即文件描述符对应的那一位如过为1则监听此文件描述符,__FD_SETSIZE的值为1024即最大可以监听1024个字节,

操作fd_set采用以下宏函数

void FD_CLR(int fd, fd_set *set); // 用来清除描述词组set中相关fd 的位
int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组set中相关fd 的位是否为真
void FD_SET(int fd, fd_set *set); // 用来设置描述词组set中相关fd的位
void FD_ZERO(fd_set *set); // 用来清除描述词组set的全部位

最后一个参数设置select()的等待时间,如果填空则表示一直阻塞直到出现被监听的时间触发,传入一个struct timeval并且将时间设置为0则表示只检查一次直接返回, 时间设置为一个大于0的数表示需要等待固定的时间,如果在这段时间内无时间触发则直接返回。

返回值
执行成功则返回文件描述符状态已改变的个数
如果返回0代表在描述符状态改变前已超过timeout时间,没有返回
当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds, exceptfds的值变成不可预测。

select执行过程,先通过提供的宏函数设置相应位的文件描述符,如建设select最多只有8位,则定义一个set 通过FD_ZERO设置为0000 0000 当需要监听的fd = 5 则通过FD_SET(fd, &set)设置为0001 0000如果需要监听的fd还有 3则通过同样的办法设置为0001 0100此时通过select监听需要监听的事件,如文件描述符5事件触发则返回,此时set为 0001 0000 3的位置会被清空,可以通过FD_ISSET判断被触发的事件。

select缺点:
select可以监听的描述符是由限制的, 
其需要遍历添加的所有描述符,当fd数量特别多时开销非常大
其会清除没有触发的描述符,所以每次都需要将fd 重现添加到set中,而且需要在外面将所有添加的描述符保存起来,以供重新添加和返回时寻找触发的描述符。

poll

poll的函数原形int poll(struct pollfd *fds, nfds_t nfds, int timeout);

其中fds为监听的事件集合,用结构体数组存储,nfds为这个结构体数组元素个数,timeout是监听时间。

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

pollfd中fd为描述符,events为需要监听的事件,revents为返回的事件,

常量值eventsrevents说明
POLLINYY普通或优先带数据可读
POLLRDNORMYY普通数据可读
POLLRDBANDYY优先级带数据可读
POLLPRIYY高优先级数据可读
POLLOUTYY普通数据可写
POLLWRNORMYY普通数据可写
POLLWRBANDYY优先级带数据可写
POLLERRNY发生错误
POLLHUPNY发生挂起
POLLNVALNY描述符不是一个打开的文件

poll返回值和select相同

poll和select相比,其可以监听的描述符数量没有上限,但是poll也是一种轮训的方式,当数量特别多时,其效率会比较低,
另外poll不能跨平台使用select 可以
最后还有每次调用poll都需要把大量的pollfd结构从⽤用户态拷贝到内核中,select需要拷贝的字节数小于poll,当监听数量特别大时poll需要拷贝的数量也会增加会导致其效率线性下降。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值