I/O复用:select poll epoll相关问题

select:

  1. select每次都会将用户态数据拷贝到内核态,包括三个fd_set和time_val,最后将更改后的数据从内核态重新拷贝到用户态,这也是select效率低下的原因之一。
  2. 参数time_val,传入的是指针类型,内核会根据时间对其进行修改。
  3. select利用等待队列让用户没有可读/写/异常时睡眠,有可读写异常时唤醒。(设置NULL则一直等待,超时时间为传入的值,中途会转换为时间周期计算)
  4. select的主要工作在do_select,将其进程的状态设置为可中断阻塞状态(睡眠阻塞状态),通过检测对文件描述符对应驱动程序的poll操作(检测文件描述符是否可以操作),轮询检测监视文件描述符的位图,每有一个时间则将retval++(select的返回值,就绪的文件描述符),如果有则将进程设置为运行态,没有则阻塞睡眠等待唤醒(schedule_timeout(__timeout))。
  5. 对于驱动程序poll,先将current挂载在等待队列上(此时不阻塞),直到将其遍历完成,等待唤醒,返回值是mask值。
  6. select共开辟了6个位图,前三个用作拷贝用户态的数据,后三个用来返回结果。

 

poll:

  1. select,poll对于poll_initwait(&table)初始化,定义了其回调函数_poll_wait。_poll_wait的作用即一次设备poll调用穿件一个poll_table_entry,并将current挂载在等待队列上,之后轮询所有fd对应的poll,等待唤醒,相比select传入fdset更高效。
  2. poll对于描述符建立了pollfd,使用链表将其相连,每个节点的大小就是页面大小,所以对于文件描述符没有限制,优先在栈上创建,不足的在堆上申请。但是参数传递和页面分配也十分影响效率。
  3. poll于select在数据拷贝方面一样,每次执行都需要重新拷贝监听的时间到内核态,底层实现也基本相同。
  4. select轮询到max+1 个,而poll监听fd在pollfd中的数组里,当描述符相对离散时,poll的效率略高。

 

epoll:

  1.实现了epoll自己的文件结构eventpoll和epitem,在初始化时(操作系统启动时)分配相应的缓存,使用slab分配内存。epoll_creat返回的为新的文件描述符(仅epoll可用),可以通过file->private_data得到。

  2.高效之处体现在不必每次从用户空间拷贝数据,通过ctl进行增量操作。

  3.每次epoll_wait只返回就绪的描述符,同时有epoll_entry作为epitem的私有项(其中有等待队列),关联epitem和回掉函数(将就绪的epitem加入rdlist)。eventpoll的等待队列主要作用是将其唤醒。

  4.epoll的ET模式,每次epoll_wait后将数据拷贝到txlist后将数据发送到用户空间,仅将没有标记为ET的和状态改变的拷贝回到rdlist。

原文地址:https://www.cnblogs.com/zhangtiezi/p/8470083.html