Select 系统调用:

  select 轮询监听多个文件描述符的数组,其原理如下(转自:这里):

从用户空间拷贝fd_set到内核空间
注册回调函数__pollwait;
遍历所有fd,对全部指定设备做一次poll(这里的poll是一个文件操作,它有两个参数,一个是文件fd本身,一个是当设备尚未就绪时调用的回调函数__pollwait,这个函数把设备自己特有的等待队列传给内核,让内核把当前的进程挂载到其中);
当设备就绪时,设备就会唤醒在自己特有等待队列中的【所有】节点,于是当前进程就获取到了完成的信号。poll文件操作返回的是一组标准的掩码,其中的各个位指示当前的不同的就绪状态(全0为没有任何事件触发),根据mask可对fd_set赋值;
如果所有设备返回的掩码都没有显示任何的事件触发,就去掉回调函数的函数指针,进入有限时的睡眠状态,再恢复和不断做poll,再作有限时的睡眠,直到其中一个设备有事件触发为止。
只要有事件触发,系统调用返回,将fd_set从内核空间拷贝到用户空间,回到用户态,用户就可以对相关的fd作进一步的读或者写操作了。

  上述标红的地方都是比较耗时的,这是select的一大缺陷,此外,select只能监听有限的文件描述符(可修改内核参数)。

  select跨平台特性是其一大优点

Poll 系统调用

  Poll与Select基本一致,只是没有了监听描述字的个数限制

Select和Poll都是只支持水平触发

注:select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)

epoll 系统调用

  epoll 是linux系统才有的, 几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法:转自这里

epoll支持水平触发和边缘触发(Edge Triggered, 告诉进程哪些文件描述符刚刚发生变为就绪状态,只说一遍,如果进程没有进一步动作,将不会再次告知),

epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了这些文件描述符在系统调用时复制的开销。

另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知

  原理:转自这里

epoll原理概述

调用epoll_create时,做了以下事情:

  1. 内核帮我们在epoll文件系统里建了个file结点;
  2. 在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket;
  3. 建立一个list链表,用于存储准备就绪的事件。

调用epoll_ctl时,做了以下事情:

  1. 把socket放到epoll文件系统里file对象对应的红黑树上;
  2. 给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。

调用epoll_wait时,做了以下事情:

观察list链表里有没有数据。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已。

最新文章

  1. 51nod1134(最长递增子序列)
  2. SharePoint 2013 工作流平台的选项不可用
  3. Android中在sdcard上创建文件夹
  4. java的分层开发
  5. javaEE开发案例——购物车
  6. 安装arbotix simulator仿真环境--9
  7. javascript表单(form)序列化
  8. Linux 命令 - route: 显示或操作路由表
  9. Convert String to Long
  10. ucos_ii 上锁函数OSSchedLock()函数透析
  11. SQL Server数据库连接字符串整理
  12. 理解 Python 中的线程
  13. webService 客户端调用及异常信息First Element must contain the local name, Envelope , but found definitions
  14. 『Python』VS2015编译源码注意事项
  15. JUC-Condition线程通信
  16. j2me必备之网络开发数据处理
  17. android的左右滑动效果实现-ViewFlipper
  18. 浅尝flutter中的http请求
  19. java8新特性Lambda练习
  20. WCF错误:413 Request Entity Too Large 的一个解决方法

热门文章

  1. [转] Linux Daemon Writing HOWTO
  2. (POI)Excel格式转Html格式
  3. Java泛型类型
  4. SpringBoot(一)初遇
  5. SpringMVC入门(二)—— 参数的传递、Controller方法返回值、json数据交互、异常处理、图片上传、拦截器
  6. LeetCode Tries Prefix Tree
  7. 小tip: CSS后代选择器可能的错误认识——张鑫旭
  8. problem-solving-with-algorithms-and-data-structure-usingpython(使用python解决算法和数据结构) -- 基本数据结构 -- 队列
  9. Code Signal_练习题_commonCharacterCount
  10. 虚拟主机服务器php fsockopen函数被禁用的解决方法