仿muduo实现高并发服务器——时间轮timewheel.cpp

目录

    • 摘要
    • [1. 架构与文件构成](#1. 架构与文件构成)
    • [2. TimerTask](#2. TimerTask)
    • [3. bug1:构造顺序](#3. bug1:构造顺序)
    • [4. bug2:TimerAdd 与 Refresh](#4. bug2:TimerAdd 与 Refresh)
    • [5. bug5:TickRun](#5. bug5:TickRun)
    • [6. bug3、bug4:两套索引](#6. bug3、bug4:两套索引)
    • [7. 总结](#7. 总结)
    • [8. 常见问题](#8. 常见问题)
    • [9. 标签](#9. 标签)

# timewheel.cpp 源码走查:TimerTask 与 TimeWheel

摘要

单文件时间轮:TimerTask 持 id、超时与回调,析构中执行任务;TimeWheel 用 _timers 与 _wheel

两套索引,外部每秒 TickRun 驱动。

1. 架构与文件构成

两个类:TimerTask、TimeWheel。_timers 管 id,_wheel 管时间位置。main、TimerAdd、每秒 TickRun;到期时 clear() 释放该位置 PtrTask,无其他强引用则 ~TimerTask 执行任务,_release 回调 RemoveTimer。

【流程图占位:全链路;节点:main 循环 sleep → TickRun → (_tick+1)%_capacity → clear → ~TimerTask → RemoveTimer】

2. TimerTask

_cancel 决定两处:析构中为 true 时提前 return,回调均不执行;SetRealese 拒绝设置。SetCancel 状态未变时返回 false。

摘录(timewheel.cpp,TimerTask::SetCancel):

cpp 复制代码
    bool
    SetCancel (bool b)
    {
        if (b == _cancel)
            {
                spdlog::info ("SetCancel error 已经set过");
                return false;
            }
        _cancel = b;
        return true;
    }

3. bug1:构造顺序

声明序 _tick、_capacity、_timers、_wheel;构造列表 _wheel(_capacity) 依赖 _capacity 先声明。

摘录(timewheel.cpp,TimeWheel 私有成员):

cpp 复制代码
  private:
    int _tick;          // 滴答下标
    uint64_t _capacity; // 表盘最大数量---其实就是最大延迟时间
    // Hash-通过id进行管理 blog分析🔍销毁(shared_ptr与weak_ptr)
    std::unordered_map<uint64_t, WeakTask>
        _timers; // <id,weak_ptr> 管理销毁与创建
    std::vector<std::vector<PtrTask>>
        _wheel; // 二维时间轮

【bug1】:未顾及初始化顺序,错误的以"读顺序优先"

4. bug2:TimerAdd 与 Refresh

TimerAdd:查 _timers 去重,SetRealese 绑 RemoveTimer+this+id,插入 _wheeldelay。Refresh:pos = 超时 + _tick 取模 _capacity,再头插同一 PtrTask。

摘录(timewheel.cpp,TimeWheel::TimerAdd):

cpp 复制代码
        pt->SetRealese (std::bind (&TimeWheel::RemoveTimer, this, id));
        // _wheel[delay].push_back (pt);
        _wheel[delay].insert (_wheel[delay].begin (), pt);

【bug2】:对结构不熟悉,写代码纯粹的不细心。

5. bug5:TickRun

TickRun:遍历 _wheel(_tick + 1) % _capacity,逐个 SetCancel(false);返回 true 记 flag--,flag < 0 时打印并 return,_tick 不前进;否则 _tick 前进一格并 clear()。

摘录(timewheel.cpp,TimeWheel::TickRun):

cpp 复制代码
        for (auto &e : _wheel[(_tick + 1) % _capacity])
            {
                // if (!e->SetCancel (true))可以吗?  bug5 不可以!!
                if (e->SetCancel (false))

【bug5】:想要复用逻辑,复用仅存在一种有效方法

【流程图占位:TickRun 单次推进;节点:定下标 (_tick+1)%_capacity → 遍历 SetCancel → 失败计数 → _tick 前进 → clear()】

6. bug3、bug4:两套索引

RemoveTimer 经 _release 调用:find 失败打印 remove error,成功则 erase(id)。SetCanCel:lock() 取 GetTimeOut() 得 pos,再遍历 _wheelpos 逐个 SetCancel(true)。

摘录(timewheel.cpp,TimeWheel::RemoveTimer / SetCanCel):

cpp 复制代码
        auto it = _timers.find (id);
        if (it == _timers.end ())
            {
                spdlog::error ("remove error");
                return;
            }
cpp 复制代码
        uint32_t pos = _timers[id].lock ()->GetTimeOut ();

【bug3】

【bug4】

7. 总结

结构:任务状态 + 两套索引 + 外部驱动;

8. 常见问题

  1. lock() 为何有效?(_wheel 强引用持有)
  2. SetCancel 返回 false?(b == _cancel 时)
  3. _wheelid 能定位吗?(不能,下标是延迟距离)

9. 标签

时间轮 / C++ / 智能指针 / weak_ptr

相关推荐
Navigator_Z12 小时前
LeetCode //C - 1291. Sequential Digits
c语言·算法·leetcode
WL学习笔记13 小时前
C & C++ 内存管理
c++·c++内存管理
水饺编程15 小时前
第2章:Linux 基础,clear 命令
linux·c语言·汇编
宛 禾16 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
hetao173383716 小时前
联盟场-提高组-R7 & ZYZSC-S-Round 11
c++·算法
程序喵大人16 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
无敌贵点大王16 小时前
嵌入式软件面试经(自用)
c语言·stm32·单片机·学习·mongodb·面试·职场和发展
局部有解16 小时前
Hot100 - 三数之和
数据结构·c++·算法
学逆向的17 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全