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在内的任意函数。