select与epoll

select设计模式

 
监听一组句柄fd_set,第一次调用的时候循环全部句柄对应的驱动函数xx_poll,socket的话就是sock_poll。
循环遍历完毕以后会若是发现有可用的(活跃状态的)fd,则返回,返回的时候会返回活跃的fd个数,同时会
把不活跃的fd在fd_set移除。若是循环fd_set一遍之后发现没有活跃的fd。假设此时socket在非阻塞模式下,
那么select会重复遍历这些fd_set直到超过了咱们设置的时间限制,但是在阻塞模式下呢,怎么处理?
阻塞模式下咱们没有必要设置超时限制,由于若是第一遍变量fd_set发现没有活跃的fd那么,这条进程会被
挂起的。进程怎么被激活呢,实际上进程是被挂在了n个fd的等待队列里,只要一个fd准备就绪那么进程就
会被唤醒,网卡接收了数据包发送一个中断给内核,内核处理这个中断,唤醒进程,这里是涉及到软中断的
,有兴趣能够看看。select被唤醒以后,并不知道是哪个fd把本身唤醒的,因此还要来一个遍历,过程跟
上面说的是同样的。select阻塞到返回经历的内核和用户空间的拷贝,先把fd_set从用户空间拷贝给内核空
间,内核空间处理完毕以后把活动的fd再copy回来。其实后者还好,可是前者当fd_set百万级别的时候,就
费劲了。个中细节我并不是彻底了解,但是单看这个设计模式就觉着有效率问题了,感受真的很傻,copy不说,
这个遍历全部描述符实在是太费劲了,并且每次在调用开始时,要把当前进程放入各个文件描述符的等待队列
在调用结束后,又把进程从各个等待队列中删除。
 
 
epoll
 
epoll的实现说白了,就是新发明了一个迷你文件系统:eventpollfs。其实,这须要sock_poll驱动的辅助
才能完成这样的设计,话说若是关注到epoll和select了,还不了解一下驱动的话,是看不动的。epoll的一
组函数:epoll_create,epoll_ctl,epoll_wait,就这三个函数完成百万并发醉了么?简单的能够这么理解,
epoll_create : 建立红黑树和就绪列表,实际他建立了一个专属于epoll文件系统的一个文件
epoll_ctl      :向红黑树添加socket句柄,向内核注册回调函数,用于当中断事件来临时,向准备就绪列表插
                  入数据
epoll_wait    :返回准备就绪列表的数据
 
准备就绪列表怎么维护的呢?当咱们在作epoll_ctl时会给内核中断处理程序注册一个函数,告诉内核,若是这个句柄的中断到了,就把他放在准备就绪list链表里。
 
另外还有就是epoll的水平触发和边缘触发
 
水平触发level-triggered lT 只要知足条件就触发一个事件,只要数据没有被获取,内核会不断通知你
边缘出发edge-triggered ET 每当状态变化,触发一个事件。
具体例子吧,假设一个socket原本无数据可读,如今来了100个字节,这时候状态发生了变化,那么水平触发
和边缘出发都会被激活,但是呢,咱们此次只读了20个字节,对于水平触发来讲,还有80字节没读呢,再去监
听端口仍是应该被触发可读调用,可是对于边缘触发的设计模式来讲,由于刚才状态是从不可读变为可读,而如今是可读维持为可读,状态没变化,因此如今不必再触发可读调用了。
这只是种设计思想而已,好比epoll,在就绪列表作点名堂就能够了,好比一个socket,假设没有被读完,提供是否再次放回到就绪列表中这两个选项,就成了两种触发了。
相关文章
相关标签/搜索