cornerstone中delayed_task,timer_task及scheduler源码解析

1.概述

delayed_task在cornerstone中充当一个base类,其延伸出的子类timer_task才是cornerstone用于实现定时器的类。
而scheduler是用于实现延时效果的调度器。
我们将按照delayed_task->timer_task->scheduler的顺序解析源码。

2.delayed_task源码解析

2.1 成员变量分析

class delayed_task
{
private:
    std::atomic<bool> cancelled_;
    void* impl_ctx_;
    std::function<void(void*)> impl_ctx_del_;
}
  • cancelled_表示是否取消了任务,使用atomic是防止在多线程环境下线程不安全。
  • impl_ctx_是给task具体执行的函数impl传递的上下文参数。
  • impl_ctx_del_负责删除任务。

这里有3个知识点:

  • impl_ctx_设置成上下文参数,其是未知的,因此我们将其声明为void*
  • 为了支持包括lambda在内的任意函数,将del函数声明为std::function<void(void*)>
  • 由于task可能会被同时取消与调用,所以有多线程race-condition的情况

2.2 初始化

public:
    delayed_task() : cancelled_(false), impl_ctx_(nilptr), impl_ctx_del_()
    {
    }
    virtual ~delayed_task()
    {
        if (impl_ctx_ != nilptr)
        {
            if (impl_ctx_del_)
            {
                impl_ctx_del_(impl_ctx_);
            }
        }
    }

没什么好说的,就是对2.1成员分析的应用。

2.3 task执行

public:
    void execute()
    {
        if (!cancelled_.load())
        {
            exec();
        }
    }

execute是这个delayed_task对外提供的public接口,具体实现放在了exec里面,实现接口与实现分离。

protected:
    virtual void exec() = 0;

声明成virtual从而让子类实现。
(即使声明成private也可以让子类实现,这是nvi(non-virtual-interface)技巧)

3.timer_task源码解析

template <typename T>
class timer_task : public delayed_task
{
using executor = std::function<void(T)>;
private:
    executor exec_;
    T ctx_;
}

首先看成员变量,exec_即为具体的执行函数,ctx_即为exec_所需要的上下文参数。

然后到执行

protected:
    virtual void exec() __override__
    {
        if (exec_)
        {
            exec_(ctx_);
        }
    }

这里实现了基类声明的exec,执行前判断exec_是否有效。

4.scheduler源码解析

class delayed_task_scheduler
{
    __interface_body__(delayed_task_scheduler);

public:
    virtual void schedule(ptr<delayed_task>& task, int32 milliseconds) = 0;

    void cancel(ptr<delayed_task>& task)
    {
        cancel_impl(task);
        task->cancel();
    }

private:
    virtual void cancel_impl(ptr<delayed_task>& task) = 0;
};
}

schedule的任务就是负责将task延后milliseconds后执行。
同样的这里是声明为纯虚函数由子类实现。

子类的实现:

void asio_service::schedule(ptr<delayed_task>& task, int32 milliseconds)
{
    if (task->get_impl_context() == nilptr)
    {
        task->set_impl_context(new asio::steady_timer(impl_->io_svc_), &_free_timer_);
    }
    // ensure it's not in cancelled state
    task->reset();

    asio::steady_timer* timer = static_cast<asio::steady_timer*>(task->get_impl_context());
    timer->expires_after(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(milliseconds)));
    timer->async_wait([task](const asio::error_code err) mutable { _timer_handler_(task, err); });
}
void asio_service::cancel_impl(ptr<delayed_task>& task)
{
    if (task->get_impl_context() != nilptr)
    {
        static_cast<asio::steady_timer*>(task->get_impl_context())->cancel();
    }
}
  • 注意这里scheduler传入的参数是ptr<delayed_task>& task,但是在cornerstone里面真正用于定时器的是timer_task,这里存在多态的转换。
  • 利用asio中的steady_timer,将task绑定到timer上面
  • timer->expires_after设置定时器到期时间,timer->async_wait异步等待定时器到期,_timer_handler_(task, err);timer过期时调用回调函数执行task从而实现schedule功能

5.总结

  • 1.使用atomic实现多线程无锁编程。
  • 2.利用void*传入任意类型参数,利用 std::function<void(void*)>支持包括lambda在内的任意函数。
posted @ 2024-11-20 22:01  TomGeller  阅读(2)  评论(0编辑  收藏  举报