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()到真正的定时器函数调用才最终完成。

下面是比较清晰的时序图。

 

posted @ 2020-09-01 23:59  WoodInEast  阅读(243)  评论(0编辑  收藏  举报