class

Reactor模式

      它要求主线程(I/O处理单元,项目中是server类)只负责监听文件描述符上是否有事件发生,有的话就立即通知工作线程(逻辑单元),除此之外,server类(主线程mainLoop)不做任何实质性工作.读写数据,接受新的连接,以及处理客户请求均在工作线程中完成

工作流程(使用同步I/O模型)
  1. one loop per thread
  2. 创建threadnum个大小的线程
  3. 主线程创建监听描述符,在server类中实现了连接回调,将接受到的连接绑定到epoll事件列表中
  4. 新的连接将分配一个eventloop给其使用,实现one loop per thread
  5. 监听连接的数据可读事件

EventLoop

      
1.基于muduo中one loop per thread的思想,我们需要创建一个线程池,给新到来的每个连接run一个Eventloop, 在构造函数中,需要检查当前thread是否已经创建了其他EventLoop对象

  1. 在IO线程中执行用户任务回调,EventLoop::runInLoop(const Fucntor &cb);如果用户在其他线程中执行调用runInLoop,cb会加入队列,IO线程会被唤醒来执行这个functor
    2.1 因为IO线程平时会阻塞在IO复用函数epoll_wait的调用当中,为了能让IO线程立即执行用户回调, 通过设立wakeupFd_来唤醒IO线程
    2.2 doPendingFuctor()中通过把回调列表swap()到局部变量functors中: 1.减小临界区长度(意味着不会阻塞其他线程调用queueInLoop()来往pendingFunctors中添加新的回调); 2.避免了死锁(添加回调时可能会再调用queueInLoop, 而对于pendingFunctors需要加锁操作)

Epoller

  1. IO复用的封装,其owner EventLoop在IO线程中调用,无需加锁。生命期与EventLoop相等。Epoller不拥有Channel,Channel在析构的时候必须自己unregister,避免出现空悬指针
  2. 不能一边Epoller::poll()一边Channel::handleEvents(),因为后者会添加或者删除Channel,从而造成其在poll的过程中出现Channellist大小改变的情况;让Epoller::poll()只负责IO复用,不负责事件分发(dispatching)

Channel

  1. 每个Channel从属于一个EventLoop中,在构造函数中通过绑定EventLoop和connfd来构建一个新的Channel,负责该connfd的IO事件的分发
  2. events_是channel关心的IO事件,由用户设置
  3. revents_是目前活动的事件,由EventLoop/Epoller设置
  4. Channel并不拥有该connfd,在析构时也不会关闭该connfd

你可能感兴趣的:(class)