muduo库源码分析3——muduo事件循环分析

muduo事件循环分析

        muduo网络库网络I/O模型为非阻塞reactor模式。使用linuxepollpoll系统调用,轮寻多个socket,然后利用事先注册的事件句柄处理发生事件的套接字。

muduo中一个thread与一个EventLoop绑定,即“one-loop-per-thread模式,线程的主循环核心代码:

while(1){

  1) poller_->poll();

  2) for(...){

    /*处理发生事件的socket*/

    handleEvent();

  }

  3) doPendingFunctors();

}

        其中,muduo使用timerfd定时器描述符,可以像处理普通文件描述符一样处理定时器。因此1)2)两个步骤完成文件描述符的同步处理操作。而步骤3)执行函数列表中积压的函数对象(muduo规定,一个socket的事件句柄只能由其注册的线程调用,如果其他线程想要调用必须将包含参数的回调函数对象投递到目标线程时间循环的函数列表中异步执行),完成异步操作。

事件循环中的定时器

        muduo库中的定时器采用timerfd,因此需要使用selectpollepoll等检测,另外muduo的定时器不是严格定时器。为了实现定时器功能,涉及的对象主要有TimerTimestampTimerQueue。其中Timer对象为定时器本体,包括定时器时限和超时回调函数;Timestamp是时间戳,主要用于比较定时器到期否;TimerQueue对象用于存储Timer(使用二叉搜索树set<>存储),并在EventLoop中注册channel,定时器超时后调用handleRead函数,依次处理所有超时定时器。

启动TimerQueue

>muduo_net_::EventLoop loop
| >timerQueue_(new TimerQueue(this)) //构造TimerQueue对象
| | >timerfd_(createTimerfd())
| | | >return ::timerfd_create(CLOCK_MONOTONIC,TFD_NONBLOCK | TFD_CLOEXEC) //申请timefd描述符
| >timerfdChannel_(loop, timerfd_) // 关联timerfd_Channel对象
| >timerfdChannel_.setReadCallback(boost::bind(&TimerQueue::handleRead, this)); //绑定超时处理
| >timerfdChannel_.enableReading(); //timerfd_描述符添加poll事件源

添加定时器Timer,调用EventLoop::runAt \ runAfter \ runEvery均会调用TimerQueue::addTimer函数

>timerQueue_->addTimer(cb, time, interval);
| >Timer* timer = new Timer(cb, when, interval); // 构造新的定时器对象
| >loop_->runInLoop(boost::bind(&TimerQueue::addTimerInLoop, this, timer)); //添加定时器到EventLoop
| |>bool earliestChanged = insert(timer); // Timer对象插入set<>
| | >resetTimerfd(timerfd_, timer->expiration()); // 重置timerfd描述符

定时器超时处理

>currentActiveChannel_->handleEvent(pollReturnTime_); //EventLooploop函数中调用
| >即调用TimerQueue::handleRead() //timerfd的事件处理函数
| | >std::vector expired = getExpired(now); //查找set<>中所有超时的定时器
| | >for (std::vector::iterator it = expired.begin(); it != expired.end(); ++it)
| | | >it->second->run(); //即调用Timer::callback_()
| | >reset(expired, now); //清除已超时定时器,并跟新timefd描述符

你可能感兴趣的:(c/c++开发,linux开发,网络开发,muduo)