muduo源码解析26-网络库4:timerqueue类和eventloop类最终版
timerqueue类:
说明:
为什么要引用timerqueue类?
再来看一下现在reactor模型的时序图
eventloop::loop()
{
eventloop::poller::poll()
{
::poll();获取发生了网络事件的套接字
poller::fillActiveChannels();把套接字对应的channel保存到eventloop::m_activeChannels
}
channel::handleEvent()
{
让eventloop::m_activeChannels中的每个channel都进行handleEvent()
}
}
上面的过程完全是不断调用channel::handleEvent()来处理网络事件,假设现在有一个要求,就是在eventloop线程内,用户就要求能够立即执行一个函数func()。现在如果我们直接把func()插入到loop()函数体中,必须得等到poller::poll()返回(默认经过10s)才能去执行func(),这样肯定是不行的。因此我们需要用一个定时器,去唤醒这个poller::poll()使得其能够立即返回,来执行我们所需要的func()。
如何选择定时器?
timerfd是一个非常好的选择:
timerfd实质是一个定时器套接字,这个套接字上所发生的事件也可以被select,poll,epoll捕获,因此,我们只需要用timerfd完成一个定时操作,时间一到立马让timerfd发出一个可读定时器事件,这个时候poller::poll()就会捕获到这个定时器事件,然后立即返回。就可以达到立马执行func()的目的了。
这个操作其实就在24节:reactor例子哪里就已经使用过了,目的就是让timerfd发起一个可读事件立马唤醒poller::poll()的目的。
timerqueue内部就是通过timerfd_*系列函数来实现的
timerqueue.h
#ifndef TIMERQUEUE_H #define TIMERQUEUE_H #include<set> #include<vector> #include"base/mutex.h" #include"base/timestamp.h" #include"net/callbacks.h" #include"net/channel.h" namespace mymuduo{ namespace net{ class eventloop; class timer; class timerid; class timerqueue:noncopyable { public: //explicit隐式类型转换,loop为timerqueue所属于的那个eventloop explicit timerqueue(eventloop* loop); ~timerqueue(); //添加定时器到定时器集合中去,供eventloop使用来封装eventloop::runAt(),runAfter()... timerid addTimer(TimerCallback cb,timestamp when,double interval); //取消一个定时器 void cancel(timerid tid); private: typedef std::pair<timestamp,timer*> Entry; //<时间戳,定时器指针>对 typedef std::set<Entry> TimerList; //定时器集合 typedef std::pair<timer*,int64_t> ActiveTimer; //<定期器指针,int64_t> 活动定时器 typedef std::set<ActiveTimer> ActiveTimerSet; //活动定时器集合 //下面这三个函数是用于eventloop的回调使用,用于在eventloop内部管理定时器的添加删除和read //在eventloop循环内加入一个定时器 void addTimerInLoop(timer* t); //关闭eventloop内的定时器id void cancelInLoop(timerid id); //当定时器触发时调用 void handleRead(); //获取所有已过期的定时器集合 std::vector<Entry> getExpired(timestamp now); //重设已过期的定时器集合 void reset(const std::vector<Entry>& expired,timestamp now); //插入一个定时器 bool insert(timer* t); //数据成员 eventloop* m_loop; //所属于的那个eventloop const int m_timerfd; //timerfd,关联channel注册可读事件 channel m_timerfdChannel; //与timerfd关联,发生可读事件就执行timer::run() TimerList m_timers; //定时器的集合 ActiveTimerSet m_activeTimers; //当前活动定时器的集合 bool m_callingExpiredTimers; //是否正在调用定时器回调 ActiveTimerSet m_cancelingTimers; //是否正在停止定时器 }; }//namespace net }//namespace mymuduo #endif // TIMERQUEUE_H
timerqueue.cpp
#include "timerqueue.h" #include"base/logging.h" #include"net/eventloop.h" #include"net/timer.h" #include"net/timerid.h" #include<sys/timerfd.h> #include<unistd.h> namespace mymuduo { namespace net { namespace detail{ //内部使用的函数,创建一个timerfd,用于产生定时器事件:在poller::poll()获取定时器事件信息 int createTimerfd() { int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (timerfd < 0) { LOG_SYSFATAL << "Failed in timerfd_create"; } return timerfd; } //从现在到when这个时间戳还有多长时间,用timespec表示 struct timespec howMuchTimeFromNow(timestamp when) { //剩余微秒数 int64_t microseconds = when.microSecSinceEpoch() - timestamp::now().microSecSinceEpoch(); if (microseconds < 100) { microseconds = 100; //最小为100微秒 } //设置秒和毫秒 struct timespec ts; ts.tv_sec = static_cast<time_t>( microseconds / timestamp::microSecInSec); ts.tv_nsec = static_cast<long>( (microseconds % timestamp::microSecInSec) * 1000); return ts; } //从timerfd这个文件描述符上读取一个uint64_t, void readTimerfd(int timerfd, timestamp now) { uint64_t howmany; ssize_t n = ::read(timerfd, &howmany, sizeof howmany); LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); if (n != sizeof howmany) { LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; } }//namespace detail //重置timerfd void resetTimerfd(int timerfd, timestamp expiration) { // wake up loop by timerfd_settime() struct itimerspec newValue; struct itimerspec oldValue; memZero(&newValue, sizeof newValue); memZero(&oldValue, sizeof oldValue); newValue.it_value = howMuchTimeFromNow(expiration); int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); if (ret) { LOG_SYSERR << "timerfd_settime()"; } } } //explicit隐式类型转换,loop为timerqueue所属于的那个eventloop, timerqueue::timerqueue(eventloop* loop) :m_loop(loop),m_timerfd(detail::createTimerfd()), //新建timerfd m_timerfdChannel(loop,m_timerfd),m_timers(), m_callingExpiredTimers(false) { //timerqueue对象成功构造后,m_timerfd关联到m_timerfdChannel上 //当m_timerfd上读事件发生时,channel回调timerqueue::handleRead(), m_timerfdChannel.setReadCallback(std::bind(&timerqueue::handleRead,this)); m_timerfdChannel.enableReading(); //timerfd channel注册读事件,用于接受定时器事件 } //定时器结束后,禁止定时器channel的所有网络事件,并移除他. timerqueue::~timerqueue() { m_timerfdChannel.disableAll(); m_timerfdChannel.remove(); ::close(m_timerfd); //清空 TimerList ,由于 m_timers->second是个指针,应当回收内存 for(const Entry& timer:m_timers) delete timer.second; } //创建一个定时器,获取其ID,会让eventloop调用addTimerInLoop方法添加一个定时器 timerid timerqueue::addTimer(TimerCallback cb,timestamp when,double interval) { //创建一个新的timer,回调为TimerCallback,在when时触发定时器事件,每隔interval触发一次 timer *t=new timer(std::move(cb),when,interval); //在eventloop中回调 timerqueue::addTimerInLoop 用于把新建的定时器t添加到eventloop中 m_loop->runInLoop(std::bind(&timerqueue::addTimerInLoop,this,t)); return timerid(t,t->sequence());//返回创建的定时器ID } //eventloop中回调 timerqueue::cancelInLoop 用于取消一个定时器 void timerqueue::cancel(timerid tid) { m_loop->runInLoop(std::bind(&timerqueue::cancelInLoop,this,tid)); } //下面三个供eventloop回调使用 //在eventloop循环内加入一个定时器 //每当添加一个定时器的时候,m_timerfd就被设置为经过t->expiration()s就会发生 //读网络事件,此时poller::poll()会截取到这个读网络事件,然后交给m_timerfdChannel //去处理,执行timerqueue::handleRead()函数:获取到所有过期(可执行)的定时器集合, //去执行这些定时器设置好的回调函数 void timerqueue::addTimerInLoop(timer* t) { m_loop->assertInLoopThread(); //one loop one thread bool earliestChanged = insert(t); if(earliestChanged) detail::resetTimerfd(m_timerfd,t->expiration()); } //关闭eventloop内的定时器id void timerqueue::cancelInLoop(timerid tid) { m_loop->assertInLoopThread(); assert(m_timers.size() == m_activeTimers.size()); //找到这个tid的timer ActiveTimer atimer(tid.m_timer, tid.m_sequence); ActiveTimerSet::iterator it = m_activeTimers.find(atimer); if (it != m_activeTimers.end()) { //从m_timers中删除这个timer size_t n = m_timers.erase(Entry(it->first->expiration(), it->first)); assert(n == 1); (void)n; delete it->first; // FIXME: no delete please m_activeTimers.erase(it); } else if (m_callingExpiredTimers) { m_cancelingTimers.insert(atimer); } assert(m_timers.size() == m_activeTimers.size()); } //当m_timerfd可读网络事件触发时调用 void timerqueue::handleRead() { m_loop->assertInLoopThread(); timestamp now(timestamp::now()); detail::resetTimerfd(m_timerfd,now); //获取过期的定时器集合 std::vector<Entry> expired=getExpired(now); m_callingExpiredTimers=true; m_cancelingTimers.clear(); //过期的timer开始执行,在chnanel中执行 for(const Entry& it:expired) it.second->run(); //timer::run(),执行创建timer时绑定的回调函数 m_callingExpiredTimers=false; reset(expired,now); //重设过期时间 } //从m_timers中移除已到期的timer,并通过vector返回这些过期的timer std::vector<timerqueue::Entry> timerqueue::getExpired(timestamp now) { assert(m_timers.size() == m_activeTimers.size()); std::vector<Entry> expired; Entry sentry(now, reinterpret_cast<timer*>(UINTPTR_MAX)); TimerList::iterator end = m_timers.lower_bound(sentry); assert(end == m_timers.end() || now < end->first); std::copy(m_timers.begin(), end, back_inserter(expired)); m_timers.erase(m_timers.begin(), end); for (const Entry& it : expired) { ActiveTimer timer(it.second, it.second->sequence()); size_t n = m_activeTimers.erase(timer); assert(n == 1); (void)n; } assert(m_timers.size() == m_activeTimers.size()); return expired; } //重设已过期的定时器集合 void timerqueue::reset(const std::vector<Entry>& expired,timestamp now) { timestamp nextExpire; for (const Entry& it : expired) { ActiveTimer timer(it.second, it.second->sequence()); if (it.second->repeat() && m_cancelingTimers.find(timer) == m_cancelingTimers.end()) { it.second->restart(now); insert(it.second); } else { // FIXME move to a free list delete it.second; // FIXME: no delete please } } if (!m_timers.empty()) { nextExpire = m_timers.begin()->second->expiration(); } if (nextExpire.valid()) { detail::resetTimerfd(m_timerfd, nextExpire); } } //插入一个定时器 bool timerqueue::insert(timer* t) { m_loop->assertInLoopThread(); assert(m_timers.size() == m_activeTimers.size()); bool earliestChanged = false; timestamp when = t->expiration(); TimerList::iterator it = m_timers.begin(); if (it == m_timers.end() || when < it->first) { earliestChanged = true; } { std::pair<TimerList::iterator, bool> result = m_timers.insert(Entry(when, t)); assert(result.second); (void)result; } { std::pair<ActiveTimerSet::iterator, bool> result = m_activeTimers.insert(ActiveTimer(t, t->sequence())); assert(result.second); (void)result; } assert(m_timers.size() == m_activeTimers.size()); return earliestChanged; } }//namespace net }//namespace mymuduo
eventloop.h
相比较于之前的eventloop,现在拥有了计时器功能,就可以在eventloop::loop()循环体中额外执行用户定时器任务了。注意eventloop本身也有一个timerfd(m_wakeFd)用于唤醒Poller::poll()。
eventloop::m_wakeFd和timerqueue::m_timerfd都是定时器fd,都可以唤醒poller::poll(),只不过他们前者是为eventloop中的任务队列服务,另一个是为eventloop中的定时器队列服务的。
eventloop向外提供了一个任务队列pendingFunctors,用户可以向任务队列中添加要执行的任务,任务队列中有任务加入时,eventloop::m_wakeFd会立即发出一个可读定时器事件唤醒poller::poll()来执行任务队列中的任务。
eventloop向外提供了runAfter(),runAt(),runEvery()系列方法,用于定时器相关的操作,内部利用timerqueue::addTimer()来实现,在timerqueue中添加一个定时器,定时器到期queuetimer::m_timerfd就会发出一个可读定时器事件唤醒poller::poll()从而来执行定时器任务。
#ifndef EVENTLOOP_H #define EVENTLOOP_H #include"base/noncopyable.h" #include<atomic> #include<vector> #include<memory> #include<boost/any.hpp> #include"base/mutex.h" #include"base/currentthread.h" #include"net/callbacks.h" #include"base/timestamp.h" #include"net/timerid.h" namespace mymuduo { namespace net { class channel; class poller; class timerqueue; class eventloop:noncopyable { public: typedef std::function<void()> Functor; eventloop(); ~eventloop(); //eventloop的核心函数,用于不断循环,在其中调用poller::poll()用于获取发生的网络事件 void loop(); //停止loop() void quit(); //poller::poll返回时,得到其返回的事件 timestamp pollReturnTime() const{return m_pollReturnTime;} int64_t iteration() const{return m_iteration;} //timerqueue相关,讲Functor添加到任务队列m_pendingFunctors中准备执行 void runInLoop(Functor cb); void queueInLoop(Functor cb); size_t queueSize() const; //在XXX时间戳执行cb timerid runAt(timestamp time, TimerCallback cb); /// /// Runs callback after @c delay seconds. /// Safe to call from other threads. /// //在XXX秒之后执行cb timerid runAfter(double delay, TimerCallback cb); /// /// Runs callback every @c interval seconds. /// Safe to call from other threads. //每过XXX秒执行cb timerid runEvery(double interval, TimerCallback cb); /// /// Cancels the timer. /// Safe to call from other threads. //取消定时器timerid void cancel(timerid timerid); //用于在m_wakeupFd发起一个读事件,让poller::poll()立即返回,让其处理用户任务 void wakeup(); //更新channel,实际上调用了poller::updatechannel,更新poller的m_pollfds数组 void updateChannel(channel* ch); //实质让poller删除m_pollfds中的channel相关套接字 void removeChannel(channel* ch); //判断是否有该channel bool hasChannel(channel* ch); //断言,eventloop所属于的线程ID就是当前线程的ID void assertInLoopThread(); //判断是否eventloop所属于的线程ID就是当先线程的ID bool isInLoopThread() const; bool eventHandling() const{return m_eventHandling;} void setContext(const boost::any context){m_context=context;} const boost::any& getContext() const { return m_context; } boost::any* getMutableContext() { return &m_context; } //获得当前线程的那个eventloop* static eventloop* getEventLoopOfCurrentThread(); private: //LOG_FATAL void abortNotInLoopThread(); //定时器相关的,一旦m_wakeupFd发起读网络事件,就执行这个handleRead void handleRead(); //处理用户任务队列 void doPendingFunctors(); //打印当前活动的所有channel void printActiveChannels() const; typedef std::vector<channel*> ChannelList; bool m_looping; //eventloop是否正在loop std::atomic<bool> m_quit; //是否退出 bool m_eventHandling; //是否正在处理网络事件 bool m_callingPendingFunctors; //是否正在执行任务队列中的任务 int64_t m_iteration; //迭代次数 const pid_t m_threadId; //eventloop所在的那个线程ID,要求one eventloop one thread timestamp m_pollReturnTime; std::unique_ptr<poller> m_poller; //用于在loop()中调用poller::poll() std::unique_ptr<timerqueue> m_timerQueue; //定时器队列 int m_wakeupFd; //用于唤醒poller::poll()的FD std::unique_ptr<channel> m_wakeupChannel; //m_wakeupFD对应的channel boost::any m_context; //在poller::poll()中返回的activeChannels,也就是每个网络事件对应的channel ChannelList m_activeChannels; //当前活动的channel,用于handleEvent channel* m_currentActiveChannel; //当前处理到的那个channel mutable mutexlock m_mutex; //任务队列的锁 std::vector<Functor> m_pendingFunctors; //用户任务队列 }; }//namespace net }//namespace mymuduo #endif // EVENTLOOP_H
eventloop.cpp:
#include "eventloop.h" #include "base/logging.h" #include "base/mutex.h" #include "net/channel.h" #include "net/poller.h" #include "net/socketsops.h" #include "net/timerqueue.h" #include <algorithm> #include <signal.h> #include <sys/eventfd.h> #include <unistd.h> namespace mymuduo { namespace net { //供eventloop内部使用 namespace { //每个eventloop线程拥有的那个eventloop* __thread eventloop* t_loopInThisThread = 0; //poller::poll()的等待时间,超过就返回 const int kPollTimeMs = 10000; //下面这几个函数是与m_wakefd相关的,其主要作用就是为了在m_wakeFd上发出一个读网络事件 //然后poller::poll()就可以立即返回而不用等10s了 int createEventfd() { int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); if (evtfd < 0) { LOG_SYSERR << "Failed in eventfd"; abort(); } return evtfd; } #pragma GCC diagnostic ignored "-Wold-style-cast" class IgnoreSigPipe { public: IgnoreSigPipe() { ::signal(SIGPIPE, SIG_IGN); // LOG_TRACE << "Ignore SIGPIPE"; } }; #pragma GCC diagnostic error "-Wold-style-cast" IgnoreSigPipe initObj; } // namespace //构造函数,初始化成员,设置当前线程的t_loopInThisThread为this eventloop::eventloop() :m_looping(false),m_quit(false),m_eventHandling(false), m_callingPendingFunctors(false),m_iteration(0), m_threadId(currentthread::tid()), m_poller(new poller(this)), m_timerQueue(new timerqueue(this)), m_wakeupFd(createEventfd()), m_wakeupChannel(new channel(this,m_wakeupFd)), m_currentActiveChannel(NULL) { LOG_DEBUG << "eventloop created " << this << " in thread " << m_threadId; if (t_loopInThisThread) //重复创建eventloop { LOG_FATAL << "Another eventloop " << t_loopInThisThread << " exists in this thread " << m_threadId; } else { t_loopInThisThread = this; } //当m_wakeFd唤醒poller::poll()时,执行eventloop::handleRead()函数 m_wakeupChannel->setReadCallback( std::bind(&eventloop::handleRead, this)); //注册读网络事件,并把它更新到poller::m_pollfds上面 m_wakeupChannel->enableReading(); } eventloop::~eventloop() { LOG_DEBUG << "eventloop " << this << " of thread " << m_threadId << " destructs in thread " << currentthread::tid(); //取消m_wakeupChannel上的所有网络事件,并在poller中移除这个wakeupchannel m_wakeupChannel->disableAll(); m_wakeupChannel->remove(); ::close(m_wakeupFd); t_loopInThisThread = NULL; } //主要三块: //1.poller::poll() //2.channel::handleEvent() //3.处理用户任务队列 void eventloop::loop() { assert(!m_looping); assertInLoopThread(); m_looping = true; m_quit = false; // FIXME: what if someone calls quit() before loop() ? LOG_TRACE << "eventloop " << this << " start looping"; while (!m_quit) { //调用poller::poll()获取发生网络事件的套接字 //利用poller::fillactiveChannels获取套接字的channel集合 m_activeChannels.clear(); m_pollReturnTime = m_poller->poll(kPollTimeMs, &m_activeChannels); ++m_iteration; if (logger::logLevel() <= logger::TRACE) { printActiveChannels(); } //处理所有channel的网络事件 m_eventHandling = true; for (channel* ch : m_activeChannels) { m_currentActiveChannel = ch; m_currentActiveChannel->handleEvent(m_pollReturnTime); } m_currentActiveChannel = NULL; m_eventHandling = false; //处理用户任务队列 doPendingFunctors(); } LOG_TRACE << "eventloop " << this << " stop looping"; m_looping = false; } //停止eventloop::loop() void eventloop::quit() { m_quit=true; //只有别的线程让eventloop线程处理任务时,才可以唤醒 //不然的话eventloop线程自己就可以直接退出了 if (!isInLoopThread()) wakeup(); } //timerqueue相关,如果用户线程就是eventloop所在线程,直接执行即可 //否则需要把任务加到任务队列中等待执行 void eventloop::runInLoop(Functor cb) { if (isInLoopThread()) { //在eventloop线程直接执行 cb(); } else { //否则放进任务队列 queueInLoop(std::move(cb)); } } //把任务放进任务队列 void eventloop::queueInLoop(Functor cb) { { mutexlockguard lock(m_mutex); m_pendingFunctors.push_back(std::move(cb)); } if (!isInLoopThread() || m_callingPendingFunctors) { wakeup(); } } //任务队列的大小 size_t eventloop::queueSize() const { mutexlockguard lock(m_mutex); return m_pendingFunctors.size(); } //定时器相关,设定一个定时器用户执行任务,把定时器加入到m_timerQueue中 timerid eventloop::runAt(timestamp time, TimerCallback cb) { return m_timerQueue->addTimer(std::move(cb), time, 0.0); } timerid eventloop::runAfter(double delay, TimerCallback cb) { timestamp time(addTime(timestamp::now(), delay)); return runAt(time, std::move(cb)); } timerid eventloop::runEvery(double interval, TimerCallback cb) { timestamp time(addTime(timestamp::now(), interval)); return m_timerQueue->addTimer(std::move(cb), time, interval); } //取消一个定时器 void eventloop::cancel(timerid timerid) { return m_timerQueue->cancel(timerid); } //用m_wakeFd唤醒poller::poll(),使其立即返回 void eventloop::wakeup() { uint64_t one = 1; ssize_t n = sockets::write(m_wakeupFd, &one, sizeof one); if (n != sizeof one) { LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; } } //更新channel,实际上调用了poller::updatechannel,更新poller的m_pollfds数组 void eventloop::updateChannel(channel *ch) { m_poller->updateChannel(ch); } void eventloop::removeChannel(channel *ch) { assert(ch->ownerLoop() == this); assertInLoopThread(); if (m_eventHandling) { assert(m_currentActiveChannel == ch || std::find(m_activeChannels.begin(), m_activeChannels.end(), ch) == m_activeChannels.end()); } m_poller->removeChannel(ch); } bool eventloop::hasChannel(channel *ch) { assert(ch->ownerLoop() == this); assertInLoopThread(); return m_poller->hasChannel(ch); } //断言,当前线程就是eventloop所在的线程 void eventloop::assertInLoopThread() { if(!isInLoopThread()) abortNotInLoopThread(); } //... bool eventloop::isInLoopThread() const { return m_threadId==currentthread::tid(); } //获取当前线程的那个eventloop* eventloop* eventloop::getEventLoopOfCurrentThread() { return t_loopInThisThread; } //LOG_FATAL,错误:eventloop所属线程不是当前线程 void eventloop::abortNotInLoopThread() { LOG_FATAL << "eventloop::abortNotInLoopThread - eventloop " << this << " was created in threadId_ = " << m_threadId << ", current thread id = " << currentthread::tid(); } //定时器相关的,一旦m_wakeupFd发起读网络事件,就执行这个handleRead void eventloop::handleRead() { uint64_t one = 1; ssize_t n = sockets::read(m_wakeupFd, &one, sizeof one); if (n != sizeof one) { LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; } } //处理用户任务队列 void eventloop::doPendingFunctors() { std::vector<Functor> functors; m_callingPendingFunctors = true; { mutexlockguard lock(m_mutex); functors.swap(m_pendingFunctors); } for (const Functor& functor : functors) { functor(); } m_callingPendingFunctors = false; } //打印当前活动的所有channel void eventloop::printActiveChannels() const { for (const channel* ch : m_activeChannels) { LOG_TRACE << "{" << ch->reventsToString() << "} "; } } }//namespace net }//namespace mymuduo
时序图(结合具体使用的例子来看):
测试(结果不发了,就是定时器,很容易看明白):
#include "net/eventloop.h" #include "base/thread.h" #include <stdio.h> #include <unistd.h> using namespace mymuduo; using namespace mymuduo::net; int cnt = 0; eventloop* g_loop; void printTid() { printf("pid = %d, tid = %d\n", getpid(), currentthread::tid()); printf("now %s\n", timestamp::now().toString().c_str()); } void print(const char* msg) { printf("msg %s %s\n", timestamp::now().toString().c_str(), msg); if (++cnt == 20) { g_loop->quit(); } } void cancel(timerid timer) { g_loop->cancel(timer); printf("cancelled at %s\n", timestamp::now().toString().c_str()); } int main() { printTid(); sleep(1); { eventloop loop; g_loop = &loop; print("main"); //添加定时器,在XXX秒之后执行print函数 loop.runAfter(1, std::bind(print, "once1")); loop.runAfter(1.5, std::bind(print, "once1.5")); loop.runAfter(2.5, std::bind(print, "once2.5")); loop.runAfter(3.5, std::bind(print, "once3.5")); timerid t45 = loop.runAfter(4.5, std::bind(print, "once4.5")); loop.runAfter(4.2, std::bind(cancel, t45)); loop.runAfter(4.8, std::bind(cancel, t45)); //每2s执行一次print函数 loop.runEvery(2, std::bind(print, "every2")); timerid t3 = loop.runEvery(3, std::bind(print, "every3")); loop.runAfter(9.001, std::bind(cancel, t3)); loop.loop(); print("main loop exits"); } }
我们从eventloop类和timerqueue类之间的函数调用顺序来看一看是怎么完成eventloop中的定时器队列的。
---->eventloop中timerqueue对象创建完成,此时timerqueue中构造函数会建立一个timerqueue::m_timerfd和timerqueue::m_timerfdChannel,用于注册可读定时器事件和唤醒poller::poll()。
---->eventloop对象创建完成,
---->eventloop::runAfter() 这个是为用户提供操作的,用来在eventloop中设置一个定时操作。
--->eventloop::runAt()
---->timerqueue::addTimer() 到此我们可以看出来,eventloop::run_XXX系列函数归根结底就是在timerqueue中添加一个定时器并设置定时器回调函数,那么timerqueue是如何知道现在有定时器到时了呢?
---->eventloop::runInLoop(timerqueue::addTimerInLoop)
---->eventloop::queueInLoop(timerqueue::addTimerInLoop),此时任务队列不为空,eventloop::m_wakefd会立即唤醒poller::poll()执行任务队列中的函数(timerqueue::addTimerInLoop)
----->resetTimerfd(timerqueue::m_timerfd,expiration),到现在才只是完成了timerfd_settime()操作,经过expiration秒后,timerqueue::m_timerfd就会发起可读定时器事件,
---->poller::poll()被m_timerfd可读事件唤醒,通过timerqueue::m_timerChannel来处理这个可读定时器事件
------>timerqueue::m_timerChannel会回调timerqueue::handleRead()函数:1.找到所有过期的定时器集合,
2.运行这些过期定时器的回调函数。
至此,从eventloop::runAfter()到真正的定时器函数调用才最终完成。
下面是比较清晰的时序图。