Chapter 1 | Chapter 2 | Chapter 3 |
---|---|---|
并发模型 | Reactor模式 | epoll 工作模式的选择 |
程序使用的是 Reactor 处理模式。包括主线程和工作线程两部分。
主线程: 使用 epoll 作为 IO 多路复用的实现方式,主线程只负责监听文件描述符上是否有事件发生,有的话就将对应的文件描述符交给工作线程去处理。
工作线程: 在程序开始时便创建的固定数量的线程池,避免了频繁创建线程带来的资源开销。
服务器程序通常需要处理三类事件:I/O 事件,信号以及定时事件。随着网络设计模式的兴起,两种事件处理模式应运而生,同步 I/O 模型常用于实现 Reactor 模式;而异步 I/O 模型则用于 Proactor 模式。
Reactor 模式 是一种事件处理模式,它要求 主线程(I/O处理单元) 只负责监听文件描述符上是否有时间发生,有的话就将该事件通知 工作线程(逻辑单元) 除此之外,主线程不做任何其它实质性的工作。
读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。
使用同步 I/O 模型(以 epoll_wait 为例)实现的 Reactor 模式的一般工作流程是:
- 1、主线程往 epoll 内核事件表中注册 socket 上的读就绪事件。
- 2、主线程调用 epoll_wait 等待 socket 上有数据可读。
- 3、当 socket 上有数据可读时,epoll_wait 通知主线程。主线程则将可读事件放入请求队列。
- 4、睡眠在请求队列上某个工作线程被唤醒,它从 socket 读取数据,并处理客户请求,然后往epoll 内核事件表中注册 socket 上的写就绪事件。
- 5、主线程调用 epoll_wait 等待 socket 可写。
- 6、当 socket 可写,epoll_wait 通知主线程。主线程则将可写事件放入请求队列。
- 7、睡眠在请求队列上某个工作线程被唤醒,它往 socket 上写入服务器处理客户请求的结果。
流程图
LT(电平触发): 当 epoll_wait 检测到 socket 上有事件发生并将此事件通知应用程序之后,应用程序可以不用立即处理该事件。这样,当下一次调用 epoll_wait 时,还会再次向应用程序告知此事件,知道该事件被处理。
ET(边沿触发): 当 epoll_wait 检测到 socket 上有事件发生并将此事件通知应用程序之后,应用程序必须立即处理该事件。
所以: 本项目采用的 ET 模式在很大程度上降低了同一个 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。
EPOLLONESHOT 事件: 针对使用 ET 模式还是可能被触发多次,只有在 epoll_ctl 函数的文件描述符上注册 EPOLLONESHOT 事件,此时只触发一次,从而保证一个 socket 连接在任意时刻都只被一个线程处理。