[Chromium] Timer

Chromium的Timer机制实现是依据其Base库的Thread实现的

sequence_manager 持有 task queue
task queue创建task runner

TimerBase

纯虚类,抽象类型。

存放了task runner,应该是真正的用于跑定时任务的循环就存在这个类型的对象中

DelayTimerBase

继承自TimerBase,是纯虚类,被OneShotTimerRepeatingTimer继承,提供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

posted @ 2024-12-25 11:03  leno米雷  阅读(75)  评论(0)    收藏  举报