一、概述
持续
循环监听,EventLoop整合封装了Channel和Poller
并向上提供了更方便的接口来使用,也就是持续循环的获取监听结果并且根据结果调用处理函数。
Channel类起到了将fd及其相关属性封装
的作用,将fd及其感兴趣事件和发生的事件以及不同事件对应的回调函数封装在一起
Poller包含了Channel对象负责从事件监听器上获取监听信息,并有接口让Channel做出反应
。
EventLoop包含了Poller类,起到一个驱动循环
的功能,在发生事件后调用Poller的接口让Channel做出反应,这样在各个模块中传递更加方便。
每一个EventLoop都绑定了一个线程(一对一绑定),充分利用了多核cpu的能力,每一个核的线程负责循环监听一组文件描述符的集合
重要方法:EventLoop::loop()
while循环的大致逻辑比较简单。就是调用Poller::poll方法获取事件监听器上的监听结果。接下来在loop里面就会调用监听结果中每一个Channel的处理函数HandlerEvent( )。每一个Channel的处理函数会根据Channel类中封装的实际发生的事件,执行Channel类中封装的各事件处理函数。
详细介绍
一些细节
1、线程间通信
如果没有事件发生的话,他们loop所在的线程都是阻塞的。假如现在mainreactor监听到一个新用户的连接,得到了表示新用户连接的fd,以及感兴趣的事件的channel,它把这个channel怎么扔给subreactor呢?
libevent是通过socketpair,创建一个本地socket的数组,这2个socket都是可读可写的。
在muduo库中,使用的linux提供的eventfd,这个线程可以notify通知其他线程起来做事情。eventfd是系统API,在内核可以直接notify应用空间的应用程序,让它的线程起来做事情,效率高。
2、代码
具体代码
构造函数,初始化各个变量,
looping循环操作
判断EventLoop对象是否在自己的线程里面。每个线程都有一个eventloop对象,对于mainReactor线程里的eventloop,其负责接收新的连接并将新的连接给subreactor对象,那么这是有多个线程的,那么对于subreactor线程里的eventloop对象,可能是在他那个线程里面调用,也有可能在其他线程比如mainreacotor里面调用,这时候就需要判断一下在哪个线程里面。