C++ 11 学习之 ZLMediaKit代码分析解读---Timer

    Timer是一个简单的定时器实现辅助类。通过在构造函数中设置一个 function类型的 callback函数,以及时间间隔,当程序执行时,基于ZLToolkit内部的EventPoller事件循环,会定时调用回调,

    来达到定时器的作用。

ZLToolKit中,使用了大量的lambda以及function,充当回调函数,某种意义上可以在各个类之间解耦,但是增加了代码解读的复杂性。

  

class Timer {
public:
    typedef std::shared_ptr<Timer> Ptr;

    /**
     * 构造定时器
     * @param second 定时器重复秒数
     * @param cb 定时器任务,返回true表示重复下次任务,否则不重复,如果任务中抛异常,则默认重复下次任务
     * @param poller EventPoller对象,可以为nullptr,当这里为nullptr时,会自动通过singlton的实现来获取一个实例。
     * @param continueWhenException 定时回调中抛异常是否继续标记
     */
    Timer(float second,
          const function<bool()> &cb,
          const EventPoller::Ptr &poller /*=nullptr*/,
          bool continueWhenException = true );
    ~Timer();
private:
    weak_ptr<DelayTask> _tag;
    //定时器保持EventPoller的强引用
    EventPoller::Ptr _poller;
};


Timer::Timer(float second,
             const function<bool()> &cb,
             const EventPoller::Ptr &poller,
             bool continueWhenException) {
    _poller = poller;
    if(!_poller){
        _poller = EventPollerPool::Instance().getPoller();
    }
    _tag = _poller->doDelayTask(second * 1000, [cb, second , continueWhenException]() {
        try {
            if (cb()) {
                //重复的任务
                return (uint64_t) (1000 * second);
            }
            //该任务不再重复
            return (uint64_t) 0;
        }catch (std::exception &ex){
            ErrorL << "执行定时器任务捕获到异常:" << ex.what();
            return continueWhenException ? (uint64_t) (1000 * second) : 0;
        }
    });
}

Timer::~Timer() {
    auto tag = _tag.lock();
    if(tag){
        tag->cancel();    //在析构函数中,取消任务的执行
    }
}
 

在EventPoller::doDelayTask的实现中,以当前时间加上延时时间为Key,增加到multimap<uint64_t, DelayTask::Ptr> _delay_task_map中,

DelayTask::Ptr EventPoller::doDelayTask(uint64_t delayMS, function<uint64_t()> task) {
    DelayTask::Ptr ret = std::make_shared<DelayTask>(std::move(task));
    auto time_line = getCurrentMillisecond() + delayMS;
    async_first([time_line, ret, this]() {
        //异步执行的目的是刷新select或epoll的休眠时间
        _delay_task_map.emplace(time_line, ret);
    });
    return ret;
}
 

uint64_t EventPoller::flushDelayTask(uint64_t now_time)

{

        auto next_delay = (*(it->second))();
        if (next_delay) {
                //可重复任务,更新时间截止线
                _delay_task_map.emplace(next_delay + now_time, std::move(it->second));
        }

}

注意这里,如果next_delay返回 true ,将会把这个回调函数function继续增加到_delay_task_map,继续执行。

在EventPoller事件循环调度处理函数中,runLoop中,getMinDelay 会调用flushDelayTask ,执行对应的定时器回调函数。

总结:这里的Timer类结合EventPoller的捆绑实现,Timer的实现看似简单,但是作用挺大。我们在日常的编程中,可能会自己启动一个线程,然后在线程处理函数中,sleep若干时间,再调用某个特定的简单的处理函数。如果需要定时执行的任务比较多,可能会启动若干个线程。但是这里的实现,其实是通过一个线程,通过定时轮询的方式,执行若干个任务。有点任务池的概念。简单高效!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值