数据结构
epoll是由所有fd的集合和就绪fd的集合(可读可写fd)组成
其中,所有fd的集合是key-value的形式,key为fd,value为具体数据,由红黑树实现。
对比hash、btree/b++tree、红黑树实现epoll
hash:
缺点:首先需要创建一个hash表,其中每个hash槽后面都跟一个链表。在创建epoll的时候需要考虑到hash表的大小要定义多大。如果定的过小,要使用的fd过多,会导致其中的链表过长,查找耗时;如果定的过大,要使用的fd较少,则会浪费空间。因为不确定初始大小,所以hash槽后面放数组也不现实(因为不能固定长度,如果动态增加减少也很浪费空间和时间)
优点:若定义的大小与实际的fd大小相同,则查找效率很高
btree/b++tree:
适用于磁盘索引,插入和删除的效率没有红黑树高
红黑树:
查找效率高,黑节点平衡
就绪fd的集合因为不需要查找,所有都需要处理,所以可以选择队列。队列是FIFO的,而栈是FILO的,若一次处理就绪fd集合处理不完,下一次又在就绪fd集合中加入fd,则最早入栈的事件处理就很久。
epoll如何确定就绪fd
在协议栈中实现回调函数,在三次握手,recvbuffer,接收到send后的ack时调用回调函数。
这个回调函数需要做的事情:
1、通过fd(根据五元组确定的)从红黑树中查找对应节点
2、把节点加入到就绪队列
epoll提供的接口做的事情
1、epoll_create:创建一个红黑树节点
2、epoll_ctl:添加删除修改红黑树节点
3、epoll_wait:将就绪队列中的节点拷贝到用户空间,若就绪队列元素大于用户提供的参数,则用户多次调用epoll_wait来获取就绪队列元素
epoll的线程安全
epoll_ctl:对红黑树加锁,插入和删除的时候加互斥锁,插入和删除是用同一把锁的
epoll_wait:对就绪队列加锁,加自旋锁
ET(边沿)与LT(水平)
et:接受数据,调用一次回调
lt:recvbuffer中有数据,就调用回调
技术参考
视频技术参考:https://ke.qq.com/course/417774?flowToken=1041651