Reactor模式
一种高效的同步I/O模型的实现,Reactor模式要求主线程(I/O处理单元)只监听描述符是否有事情发生,有的话就通知工作线程(逻辑单元)。除此之外不做任何实质性的工作。
流程:(以epoll_wait为例)
1.主线程往epoll内核事件表注册socket读就绪事件。
2.主线程调用epoll_wait等待socket数据可读。
3.socket有数据可读时,epoll_wait通知主线程。主线程把socket可读事件放入请求队列。
4.睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理请求,然后往epoll内核事件表里注册socket上的写就绪事件。
5.主线程调用epoll_wait等待socket可写。
6.socket可写时,epoll_wait通知主线程。主线程把socket可写事件放入请求队列。
7.睡眠在请求队列上的某个工作线程被唤醒,它在socket上写入处理的结果。
上述的流程里,工作线程从请求队列取出事件以后,根据类型做对应的处理,对与可读事件做读数据和处理的操作;对于可写事件执行写的操作,因此不区分所谓的读工作线程和写工作线程
Proactor模式
一种高效的异步I/O模型的实现,Proactor模型将所有的I/O操作都交给主线程和内核来处理,工作线程只负责业务逻辑。
流程:(以aio_read和aio_write为例)
1.主线程调用aio_read函数,向内核注册socket上的读完成事件,并告诉内核缓冲区的位置,以及操作完成时如何通知应用程序(比如信号)。
2.主线程继续处理其他逻辑。
3.socket上的数据被读入用户缓冲区以后,内核向应用程序发送一个信号,通知数据已可用。
4.应用程序通过回调,选择一个工作程序来处理客户请求。工作线程处理完之后,调用aio_write函数调用向内核注册socket上的写完成事件,并告诉内核缓冲区的位置,以及操作完成时如何通知应用程序(比如信号)。
5.主线程继续处理其他逻辑。
6.当用户缓冲区的数据被写入socket之后,内核向应用程序发送一个信号,通知应用程序数据发送完毕。
7.应用程序通过回调,选择一个工作线程做善后处理,比如关闭socket。
例子中socket上的读写事件是通过aio_read和aio_write注册到内核的,因此内核可以通过信号报告给应用程序socket上的读写事件。所以当主线程调用epoll_wait时仅能用来检测监听socket上的连接请求事件,而不能用来检测socket上的读写事件。
补充:模拟Proactor模式
一种用同步IO模拟Proactor的方法,主线程执行数据读写,完成之后向工作线程通知这一“完成事件”。那么工作线程就直接获得了数据读写的结果,接下来对结果逻辑处理即可。
流程:(以epoll_wait为例)
1.主线程往epoll内核事件表注册socket读就绪事件。
2.主线程调用epoll_wait等待socket数据可读。
3.socket有数据可读时,epoll_wait通知主线程。主线程把从socket循环读取数据,直到没有数据可读,然后把读取到的数据封装成一个请求对象并插入请求队列。
4.睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理请求,然后往epoll内核事件表里注册socket上的写就绪事件。
5.主线程调用epoll_wait等待socket可写。
6.socket可写时,epoll_wait通知主线程。主线程把socket可写事件放入请求队列。
7.睡眠在请求队列上的某个工作线程被唤醒,它在socket上写入处理的结果。
(之后的总结不一定按模块来,觉得自己哪里欠缺就先看哪里)
网友评论