[Chromium] Timer
Chromium的Timer机制实现是依据其Base库的Thread实现的
sequence_manager 持有 task queue
task queue创建task runner
TimerBase
纯虚类,抽象类型。
存放了task runner,应该是真正的用于跑定时任务的循环就存在这个类型的对象中
DelayTimerBase
继承自TimerBase,是纯虚类,被OneShotTimer
和RepeatingTimer
继承,提供timer的基础逻辑
- 提供设置消息循环的逻辑,相当于指定定时器运行的线程,可以通过设置一个单独为Timer而生的线程
RunUserTask
执行任务的实现是纯虚函数由各个具有特色的Timer实现ScheduleNewTask
启动任务
void DelayTimerBase::ScheduleNewTask(TimeDelta delay) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!delayed_task_handle_.IsValid());
// Ignore negative deltas.
// TODO(pmonette): Fix callers providing negative deltas and ban passing them.
if (delay < TimeDelta())
delay = TimeDelta();
if (!timer_callback_) {
timer_callback_ = BindRepeating(&DelayTimerBase::OnScheduledTaskInvoked,
Unretained(this));
}
delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTask(
base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_,
delay);
desired_run_time_ = Now() + delay;
}
RepeatingTimer
RunUserTask
会执行任务,但是不会停止计时器,并使用延时时间启动新的任务ScheduleNewTask
OneShotTimer
在执行任务的时候会把这个timer停止掉
这就涉及到如何发布一个可取消任务。
RunUserTask
会停止计时器功能并执行任务
void OneShotTimer::RunUserTask() {
// Make a local copy of the task to run. The Stop method will reset the
// |user_task_| member.
OnceClosure task = std::move(user_task_);
Stop();
DCHECK(task);
std::move(task).Run();
// No more member accesses here: |this| could be deleted at this point.
}
题外话之多线程模型中的可取消任务
插入任务到任务队列的时候或持有一个句柄,通过这个句柄取消对应的任务。
实际上实现是这样的,针对传进来的任务再包一层
OnceClosure DefaultDelayedTaskHandleDelegate::BindCallback(
OnceClosure callback) {
DCHECK(!IsValid());
return BindOnce(&DefaultDelayedTaskHandleDelegate::RunTask,
weak_ptr_factory_.GetWeakPtr(), std::move(callback));
}
相当于用自身的一个成员弱指针来控制外包的这层任务的有效性,真正取消任务的时候直接把成员变量保存的弱指针无效化。
void DefaultDelayedTaskHandleDelegate::CancelTask() {
weak_ptr_factory_.InvalidateWeakPtrs();
}
任务并没有直接消失或者取消,而是被无效化,在任务到期时,被直接丢弃
重新设置触发时间
不能复用任务,丢弃当前任务开始一个新的任务,通过posttask时候拿到的handle取消任务,并发布新的任务然后刷新handle,是个简单的方法。
总结
- 可重入的设置触发时间
- 可取消的定时器任务
- 已经启动的定时器任务,再次启动后的表现
- 强制timer立刻触发
- 重复的定时器如何再次触发
- 稳定的消息循环
基于上述代码参考,稳定的消息循环采用单独的线程跑定时器任务,取消使用weak_ptr或者active标记位来实现,牺牲一部分内存销毁的不及时来简单实现的timer,献丑了!https://github.com/lenomirei/Timer/tree/master