当前位置: 首页 > article >正文

C++八股 —— 手撕定时器

文章目录

    • 1. 什么是定时器
    • 2. 需要考虑的问题吧
    • 3. 接口设计
    • 4. 完整代码
    • 5. 性能优化

来自:腾讯百度C++二面:手撕定时器_哔哩哔哩_bilibili

腾讯、网易、百度C++

手撕定时器

相关概念参考

  • C++八股——函数对象、Lambda、bind、function_c++八股文-CSDN博客
  • C++八股——网络编程之IO多路复用-CSDN博客

1. 什么是定时器

定时器(Timer)是用来管理大量延时任务(异步执行,一般用回调函数)的模块,它会触发执行最近将要超时的任务。

2. 需要考虑的问题吧

  • 如何选择数据结构

    需要满足以下要求:

    • 触发时刻作为key,任务作为val
    • 能快速找到最近要超时的任务
    • 触发后要删除该任务且支持随时删除任务
    • 允许相同时刻触发任务

    一些框架中使用的数据结构是最小堆、红黑树和时间轮。

    这里我们可以使用STL中的multimap(基于红黑树)

  • 设计“任务”

    使用函数对象

  • 如何触发

    • 使用epoll_wait中的第四个参数 —— 超时参数
    • timerfd有三个接口,记忆难度较大,可以不考虑

3. 接口设计

  • 添加一个延时任务
  • 删除一个延时任务
  • 检测触发延时任务

4. 完整代码

timer.h

#include <sys/epoll.h>
#include <functional>
#include <chrono>
#include <map>
#include <memory>
#include <iostream>class Timer;
class TimerTask {friend class Timer;
public:using Callback = std::function<void(TimerTask* task)>;TimerTask(uint64_t addtime, uint64_t exectime, Callback func) {m_addtime = addtime;m_exectime = exectime;m_func = std::move(func);}uint64_t AddTime() const {return m_addtime;}uint64_t ExecTime() const {return m_exectime;}private:void run() {m_func(this);}uint64_t m_addtime;uint64_t m_exectime;Callback m_func;
};class Timer {using Millisecond = std::chrono::milliseconds;
public:static uint64_t GetTick() {// 获取系统启动到现在时刻经过的时间auto sc = std::chrono::time_point_cast<Millisecond>(std::chrono::steady_clock::now());auto temp = std::chrono::duration_cast<Millisecond>(sc.time_since_epoch());return temp.count();}// 添加定时器,std::shared_ptr<TimerTask> AddTimeout(uint64_t offset, TimerTask::Callback func) {uint64_t now = GetTick();uint64_t exectime = now + offset;auto task = std::make_shared<TimerTask>(now, exectime, std::move(func));if (m_timeouts.empty() || exectime >= m_timeouts.crbegin()->first) {auto ele = m_timeouts.emplace_hint(m_timeouts.end(), exectime, task);return ele->second;}auto ele = m_timeouts.emplace(exectime, task);return ele->second;}// 删除定时器,由于存在多个同时触发的定时器,所以需要在满足触发时间的任务重寻找需要删除的定时器void DelTimeout(std::shared_ptr<TimerTask> task) {auto range = m_timeouts.equal_range(task->ExecTime());for (auto it = range.first; it != range.second;) {if (it->second == task) {it = m_timeouts.erase(it);} else {++it;}}}// 更新定时器void Update(uint64_t now) {auto it = m_timeouts.begin();while (it != m_timeouts.end() && it->first <= now) {it->second->run();// delete it->second;it = m_timeouts.erase(it);}}// 获取最近的超时时间int WaitTime() {auto it = m_timeouts.begin();if (it == m_timeouts.end()) {return -1;}int diss = it->first - GetTick();return diss > 0 ? diss : 0;}private:std::multimap<uint64_t, std::shared_ptr<TimerTask>> m_timeouts;
};

example.cpp

#include "timer.h"using namespace std;int main() {int epfd = epoll_create(1);unique_ptr<Timer> timer = make_unique<Timer>();int i = 0;timer->AddTimeout(1000, [&](TimerTask* task) {cout << Timer::GetTick() << " addtime:" << task->AddTime() << " revoked times:" << ++i << endl;});timer->AddTimeout(2000, [&](TimerTask* task) {cout << Timer::GetTick() << " addtime:" << task->AddTime() << " revoked times:" << ++i << endl;});timer->AddTimeout(3000, [&](TimerTask* task) {cout << Timer::GetTick() << " addtime:" << task->AddTime() << " revoked times:" << ++i << endl;});auto task = timer->AddTimeout(2100, [&](TimerTask* task) {cout << Timer::GetTick() << " addtime:" << task->AddTime() << " revoked times:" << ++i << endl;});timer->DelTimeout(task);cout << "now time:" << Timer::GetTick() << endl;epoll_event ev[64] = {};while(true) {cout << "waittime:" << timer->WaitTime() << endl;int n = epoll_wait(epfd, ev, 64, timer->WaitTime());time_t now = Timer::GetTick();for (int i = 0; i < n; i++) {/**/}timer->Update(now);}return 0;
}

5. 性能优化

  • 针对 不同功能或不同对象 设置定时器

  • 针对多线程进行优化:一个时间线程一个定时器 或者 单独时间轮线程

  • 针对有规律的定时任务(有大量相同时间间隔的延时任务)

    采用emplace_hint接口,如timer.h中的52 - 55

    emplace_hint函数可以在指定的迭代器后面插入元素,它可以提高插入效率,因为它减少了元素的移动和复制操作。通过提供插入位置的提示,emplace_hint 可以尽可能地减少容器的重新分配和元素的移动,特别是在有序容器中插入元素时,这种优化尤为明显。

相关文章:

C++八股 —— 手撕定时器

文章目录 1. 什么是定时器2. 需要考虑的问题吧3. 接口设计4. 完整代码5. 性能优化 来自&#xff1a;腾讯百度C二面&#xff1a;手撕定时器_哔哩哔哩_bilibili 腾讯、网易、百度C&#xff1a; 手撕定时器 相关概念参考&#xff1a; C八股——函数对象、Lambda、bind、functi…...

K8S-statefulset-mysql-ha

需求 实现一个HA mysql&#xff0c;包括1个master&#xff0c;2个slave。在K8S上已statefulset部署。 mysql HA原理 略 K8S环境需要解决的问题 1、由于使用同一个statefulset配置&#xff0c;因此需要考虑master和slave使用不同的cnf文件。 2、不同pod之间文件的传输 3、…...

【方案分享】展厅智能讲解:基于BLE蓝牙Beacon的自动讲解触发技术实现

【方案分享】展厅智能讲解&#xff1a;基于BLE蓝牙Beacon的自动讲解触发技术实现 让观众靠近展品即可自动弹出讲解页面&#xff0c;是智能展厅的核心功能之一。本文将从软硬件技术、BLE Beacon原理、微信小程序实现、优劣对比与拓展方案五个维度&#xff0c;系统讲解“靠近展台…...

web常见的攻击方式有哪些?如何防御?

Web常见攻击方式及防御策略 SQL注入 (SQL Injection) 详细解析: SQL 注入是一种利用应用程序未正确验证用户输入的漏洞&#xff0c;通过向应用传递恶意 SQL 查询来操纵数据库的行为。这种攻击可能导致敏感数据泄露、篡改或删除。 步骤: 攻击者找到可接受动态参数的应用程序…...

力扣:《螺旋矩阵》系列题目

今天做了一下螺旋矩阵主题的一系列题目 即力扣中的相似题目 还是有所感悟的 接下来一一回顾&#xff1a; 第一题&#xff1a; 59. 螺旋矩阵 II - 力扣&#xff08;LeetCode&#xff09; 这题让我们生成一个正方形的矩阵&#xff0c;注意是正方形&#xff0c;不是长方形&a…...

发电厂进阶,modbus TCP转ethernet ip网关如何赋能能源行业

案例分享&#xff1a;稳联技术modbus TCP转ethernet ip网关wl-abc004赋能&#xff0c;发电厂自动化改造&#xff0c;推动能源行业智能化升级 随着全球能源结构转型和“双碳”目标的推进&#xff0c;传统发电厂&#xff08;如火电、水电、生物质发电&#xff09;正面临严峻挑战&…...

深入了解linux系统—— 操作系统的路径缓冲与链接机制

前言 在之前学习当中&#xff0c;我们了解了被打开的文件是如何管理的&#xff1b;磁盘&#xff0c;以及ext2文件系统是如何存储文件的。 那我们要打开一个文件&#xff0c;首先要先找到这个文件&#xff0c;操作系统又是如何去查找的呢&#xff1f; 理解操作系统搜索文件 …...

Ansible快速入门指南

Ansible 是一款基于 Python 开发的开源自动化运维工具&#xff0c;主要用于实现服务器配置管理、应用部署、任务自动化执行等功能。它通过 简单的 YAML 脚本&#xff08;Playbook&#xff09; 定义任务&#xff0c;结合 SSH 协议 对远程主机进行管理&#xff0c;无需在被控节点…...

华为2025年校招笔试真题手撕教程(一)

一、题目 输入&#xff1a; 第一行为记录的版本迭代关系个数N&#xff0c;范围是[1&#xff0c;100000]; 第二行到第N1行&#xff1a;每行包含两个字符串&#xff0c;第一个字符串为当前版本&#xff0c;第二个字符串为前序版本&#xff0c;用空格隔开。字符串包含字符个数为…...

第9.2讲、Tiny Decoder(带 Mask)详解与实战

自己搭建一个 Tiny Decoder&#xff08;带 Mask&#xff09;&#xff0c;参考 Transformer Encoder 的结构&#xff0c;并添加 Masked Multi-Head Self-Attention&#xff0c;它是 Decoder 的核心特征之一。 1. 背景与动机 Transformer 架构已成为自然语言处理&#xff08;NLP…...

postgresql 常用参数配置

#01 - Connection-Authentication 优化点&#xff1a; listen_addresses 0.0.0.0 建议&#xff1a;生产环境应限制为具体IP&#xff08;如 192.168.1.0/24,127.0.0.1&#xff09;&#xff0c;避免暴露到公网。 ssl off 建议&#xff1a;启用SSL&#xff08;ssl on&#xf…...

Python模块中的私有命名与命名空间管理:深入解析与实践指南

文章大纲 引言 在Python开发中,模块是代码组织和复用的重要方式,而私有命名和命名空间管理则是确保代码清晰和避免冲突的关键机制。私有命名通过特定的命名约定限制了模块中某些内容的访问,有效保护了内部实现细节;命名空间管理则帮助开发者理解标识符的作用域和查找规则…...

基于PCRLB的CMIMO雷达网络多目标跟踪资源调度

针对分布式组网CMIMO雷达多目标跟踪(MTT)场景&#xff0c;博客分析了一种目标-雷达匹配方案与功率联合优化算法。在采用分布式组网融合架构的基础上&#xff0c;推导包含波束和功率分配的后验克拉美罗界(PCRLB)。随后&#xff0c;将该效用函数结合CMIMO雷达系统资源&#xff0c…...

AtCoder Beginner Contest 407(ABCDE)

A - Approximation 翻译&#xff1a; 给你一个正整数 A 和一个正奇数 B。 请输出与实数 的差最小的整数。 可以证明&#xff0c;在约束条件下&#xff0c;这样的整数是唯一的。 思路&#xff1a; 令。比较来判断答案。 实现&#xff1a; #include<bits/…...

VILT模型阅读笔记

代码地址&#xff1a;VILT Abstract Vision-and-Language Pre-training (VLP) has improved performance on various joint vision-andlanguage downstream tasks. Current approaches to VLP heavily rely on image feature extraction processes, most of which involve re…...

掌握 npm 核心操作:从安装到管理依赖的完整指南

图为开发者正在终端操作npm命令&#xff0c;图片来源&#xff1a;Unsplash 作为 Node.js 生态的基石&#xff0c;npm&#xff08;Node Package Manager&#xff09;是每位开发者必须精通的工具。每天有超过 1700 万个项目通过 npm 共享代码&#xff0c;其重要性不言而喻。本文…...

OpenCV CUDA模块特征检测与描述------一种基于快速特征点检测和旋转不变的二进制描述符类cv::cuda::ORB

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::ORB 是 OpenCV 库中 CUDA 模块的一部分&#xff0c;它提供了一种基于快速特征点检测和旋转不变的二进制描述符的方法&#xff0c;用于…...

Awesome ChatGPT Prompts:释放AI对话潜力的开源利器

项目概览 Awesome ChatGPT Prompts 是由土耳其开发者 Fatih Kadir Akın 发起的开源项目,托管于 GitHub,旨在通过精心设计的提示词模板(Prompts)优化用户与 ChatGPT 的交互体验。项目以 Markdown 和 CSV 格式管理模板,无需复杂编程语言,但需文本处理能力,目前已在 GitH…...

Prompt Tuning:轻量级微调与反向传播揭秘

Prompt Tuning 损失函数与反向传播原理解析 在Transformers中,Prompt Tuning是一种轻量级参数高效微调方法,其核心思想是只训练额外添加的提示词向量(prompt embeddings),而冻结预训练模型的主体参数。 损失函数设计 Prompt Tuning的损失函数与标准的语言模型训练类似,主…...

C++ 继承详解:基础篇(含代码示例)

目录 1. 什么是继承&#xff1f; 2. 继承的访问控制 3. 派生类构造与析构 (1) 构造顺序 (2) 析构顺序 4. 函数隐藏&#xff08;Name Hiding&#xff09; 1. 什么是继承&#xff1f; 继承&#xff08;Inheritance&#xff09;是面向对象编程&#xff08;OOP&#xff09;的…...

PP-YOLOE-SOD学习笔记2

一、解析X-Anylabeling标注后的json格式问题 最近在使用自动标注工具后json格式转化过程中&#xff0c;即标注框的四点坐标转换为两点坐标时&#xff0c;发现json格式的四点顺序是按顺时针方向开始的&#xff0c;那么在转换其实就是删除2、4坐标或者1、3坐标即可。 二、数据集…...

OpenLayers 加载测量控件

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图控件是一些用来与地图进行简单交互的工具&#xff0c;地图库预先封装好&#xff0c;可以供开发者直接使用。OpenLayers具有大部分常用的控件&#x…...

.NET ORM开发手册:基于SqlSugar的高效数据访问全攻略

SqlSuger是一个国产&#xff0c;开源ORM框架&#xff0c;具有高性能&#xff0c;使用方便&#xff0c;功能全面的特点&#xff0c;支持.NET Framework和.NET Core&#xff0c;支持各种关系型数据库&#xff0c;分布式数据库&#xff0c;时序数据库。 官网地址&#xff1a;SqlS…...

【PostgreSQL】数据探查工具1.0研发可行性方案

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 想抢先解锁数据自由的宝子,速速戳我!评论区蹲一波 “蹲蹲”,揪人唠唠你的超实用需求! 【PostgreSQL】数据探查工具1.0研发可行性方案,数据调研之秒解析数据结构,告别熬夜写 SQL【PostgreSQL】数据探查工具…...

C++ 内存管理与单例模式剖析

目录 引言 一、堆上唯一对象&#xff1a;HeapOnly类 &#xff08;一&#xff09;设计思路 &#xff08;二&#xff09;代码实现 &#xff08;三&#xff09;使用示例及注意事项 二、栈上唯一对象&#xff1a;StackOnly类 &#xff08;一&#xff09;设计思路 &#xff0…...

算法学习——从零实现循环神经网络

从零实现循环神经网络 一、任务背景二、数据读取与准备1. 词元化2. 构建词表 三、参数初始化与训练1. 参数初始化2. 模型训练 四、预测总结 一、任务背景 对于序列文本来说&#xff0c;如何通过输入的几个词来得到后面的词一直是大家关注的任务之一&#xff0c;即&#xff1a;…...

win10使用nginx做简单负载均衡测试

一、首先安装Nginx&#xff1a; 官网链接&#xff1a;https://nginx.org/en/download.html 下载完成后&#xff0c;在本地文件中解压。 解压完成之后&#xff0c;打开conf --> nginx.config 文件 1、在 http 里面加入以下代码 upstream GY{#Nginx是如何实现负载均衡的&a…...

2025电工杯数学建模B题思路数模AI提示词工程

我发布的智能体链接&#xff1a;数模AI扣子是新一代 AI 大模型智能体开发平台。整合了插件、长短期记忆、工作流、卡片等丰富能力&#xff0c;扣子能帮你低门槛、快速搭建个性化或具备商业价值的智能体&#xff0c;并发布到豆包、飞书等各个平台。https://www.coze.cn/search/n…...

软考软件评测师——软件工程之开发模型与方法

目录 一、核心概念 二、主流模型详解 &#xff08;一&#xff09;经典瀑布模型 &#xff08;二&#xff09;螺旋演进模型 &#xff08;三&#xff09;增量交付模型 &#xff08;四&#xff09;原型验证模型 &#xff08;五&#xff09;敏捷开发实践 三、模型选择指南 四…...

前端表单中 `readOnly` 和 `disabled` 属性的区别

前端表单中 readOnly 和 disabled 属性的区别 定义与适用范围 readOnly 是一种属性&#xff0c;仅适用于 <input> 和 <textarea> 元素。当设置了此属性时&#xff0c;用户无法修改这些元素的内容&#xff0c;但仍能聚焦并选中文本。disabled 则是一个更广泛的属性…...