29.muduo学习笔记之net_EventLoop.{h&cc}

1. 说明

  1. 一个EventLoop类,任何一个线程,只要创建并运行了EventLoop,都称之为IO线程(为了方便使用,定义了EventLoopThread类,封装了IO线程)
  2. 使用了Channel,Poller,TimerQueue,Timestamp类
  3. noncopyable

2. 变量

  1. 类型定义

    • Functor
    • ChannelList
  2. looping_; /* atomic */

    • bool类型,表示是否处于loop()函数执行中,它的值变化都在loop()函数中
  3. std::atomic quit_;

    • bool类型,判断是否退出,loop()中循环的结束条件
  4. bool eventHandling_; /* atomic */

    • 表示是否处于处理事件事件中,在loop()中poll()选择需要处理的通道(事件)后,在对这些事件的处理过程中把这个变量置为true
  5. bool callingPendingFunctors_; /* atomic */

    • 是否处于doPendingFunctors()函数中
  6. int64_t iteration_;

    • 在构造函数中赋初值为0,以后只在loop()中有用到,即每次poll()后+1,应该是记录poll()的次数吧
  7. const pid_t threadId_

    • 当前对象所属线程id
  8. Timestamp pollReturnTime_;

    • 调用poll(),返回时间戳
  9. std::unique_ptr poller_;

    • 每个EventLoop都会有一个Poller,
  10. std::unique_ptr timerQueue_;

    • 每个EventLoop都有个TimerQueue,定时器列表,作为定时器
  11. int wakeupFd_;

    • 用于eventfd,在构造函数中用createEventfd()生成eventfd赋值,作为线程唤醒需要使用的fd
    • 进程间通信有几种方式:pipe,socket,eventfd,线程间通信还有条件变量等
  12. std::unique_ptr wakeupChannel_;

    • 该通道将会纳入poller_来管理,用来唤醒当前线程,这是一个内部channel,不会暴露给用户
  13. boost::any context_;

    • boost::any,任意数据类型,C++17也加入C++标准
  14. ChannelList activeChannels_;

    • Poller返回的活动通道
  15. Channel* currentActiveChannel_;

    • 当前正在处理的活动通道
  16. mutable MutexLock mutex_;

    • 锁,没什么说的
  17. std::vector pendingFunctors_ GUARDED_BY(mutex_)

    • Functor的队列,这个就是需要处理的functor队列,在doPendingFunctors()函数中处理完就清空了,要理解需要结合runInLoop(),queueInLoop()等函数

3. 函数

1. 私有

  1. void abortNotInLoopThread();

    • 打印日志并退出,当前线程和此对象线程不一样,在assertInLoopThread()中调用
  2. void handleRead(); // waked up

    • 唤醒处理函数,调用read,里面的内容没有什么意义
  3. void doPendingFunctors();

    • 不是简单的在临界区内依次调用Functor,而是把回调列表swap到functors中,这样一方面减小了临界区的长度(意味着不会阻塞其他线程的queueInLoop()),另一方面也避免了死锁(因为Functor可能再次调用queueInLoop())
    • 把pendingFunctors_交换到新的局部空间,然后逐个调用这些函数
  4. void printActiveChannels() const;

    • 把活动的channel信息打印到日志

2. 共有

  1. 构造

    • 变量的初始化,设置当前channel的读回调函数为私有函数handleRead
  2. 析构

    • 释放资源
  3. void loop()

    • 循环调用poller_->poll(),返回需要处理的通道channel,处理这些通道的回调函数
    • 最后doPendingFunctors(),处理其他线程或者当前线程异步增加的需要处理的函数,详见下面的runInLoop()和queueInLoop(),这样让IO线程也能处理一些计算任务
  4. void quit()

    • 把quit_置为true,如果不是由当前IO线程调用的,要先用wakeup()唤醒当前线程
  5. Timestamp pollReturnTime()

    • 返回pollReturnTime_
  6. int64_t iteration()

    • 返回iteration_
  7. void runInLoop(Functor cb)

    • 在IO线程中执行某个回调函数,该函数可以跨线程调用
    • 如果在当前IO线程调用runInLoop.则同步调用cb()回调函数
    • else 如果在其他线程调用runInLoop.则调用queueInLoop(cb)异步地将cb添加到队列
  8. void queueInLoop(Functor cb)

    • 如果调用当前行数的线程不是当前IO线程,则需要唤醒,或者是当前线程,但此时正在调用pendingfunctor,也需要唤醒
  9. size_t queueSize()

    • 返回pendingFunctors_.size()
  10. TimerId runAt(Timestamp time, TimerCallback cb)

    • 就是把cb()加入定时器队列,在time时间执行
  11. TimerId runAfter(double delay, TimerCallback cb)

    • 把cd()加入定时器队列,当前时间+delay后执行
  12. TimerId runEvery(double interval, TimerCallback cb)

    • 把cb()加入定时器队列,每隔interval间隔时间执行一次
  13. void cancel(TimerId timerId)

    • 调用poller_->cancel(timerId),结束这个定时器任务
  14. void wakeup()

    • 唤醒当前对象线程,实际是调用write(),这样loop()函数中的poll()就会选到当前线程,然后执行
  15. void updateChannel(Channel* channel);

    • 断言当前对象线程正在执行,调用poller_->updateChannel(channel);
  16. void removeChannel(Channel* channel);

    • 保证能找到这个channel,调用poller_->removeChannel(channel);移除这个channel
  17. bool hasChannel(Channel* channel)

    • 调用poller_->hasChannel(channel);
  18. void assertInLoopThread()

    • 如果当前线程不是本对象线程,就调用abortNotInLoopThread(),打印日志并退出
  19. bool isInLoopThread()

    • 就是判断threadId_和当前正在运行的线程id是否相同
  20. bool eventHandling()

    • 返回eventHandling_,看是否处于loop()处理事件过程中
  21. void setContext(const boost::any& context)

    • 如名
  22. const boost::any& getContext()

    • 如名
  23. boost::any* getMutableContext()

    • 如名
  24. static EventLoop* getEventLoopOfCurrentThread()

    • 静态函数,返回t_loopInThisThread,即当前EventLoop对象

4. 全局

  1. t_loopInThisThread

    • 线程局部变量,在构造函数中赋值为当前对象
  2. kPollTimeMs

    • 在poll()中当参数传过去
  3. createEventfd()

    • 调用eventfd()生成eventfd返回
  4. IgnoreSigPipe类

    • 构造函数中调用signal()忽略SIGPIPE信号
    • 并且全局已经定义这个类了:initObj变量,也就是已经调用这个signal()了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值