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在內的任意函式。