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

C++ 实现定时器的两种方法(线程定时和时间轮算法修改版)

定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。也可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。

1、使用C++11中的thread, mutex, condition_variable来实现一个定时器。
注:此算法会每一个任务创建一个线程,不推荐。推荐用最下面第2种时间轮算法

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>class Timer {
public:Timer() :_expired(true), _try_to_expire(false) {}Timer(const Timer& t) {_expired = t._expired.load();_try_to_expire = t._try_to_expire.load();}~Timer() {Expire();}void StartTimer(int interval, std::function<void()> task) {if (_expired == false) {return;}_expired = false;std::thread([this, interval, task]() {while (!_try_to_expire) {std::this_thread::sleep_for(std::chrono::milliseconds(interval));task();}{std::lock_guard<std::mutex> locker(_mutex);_expired = true;_expired_cond.notify_one();}}).detach();}void Expire() {if (_expired) {return;}if (_try_to_expire) {return;}_try_to_expire = true;{std::unique_lock<std::mutex> locker(_mutex);_expired_cond.wait(locker, [this] {return _expired == true; });if (_expired == true) {_try_to_expire = false;}}}private:std::atomic<bool> _expired;std::atomic<bool> _try_to_expire;std::mutex _mutex;std::condition_variable _expired_cond;
};int main() {Timer t;t.StartTimer(1000, []() {std::cout << "Hello World!" << std::endl; });std::this_thread::sleep_for(std::chrono::seconds(4));t.Expire();return 0;
}

2、使用时间轮算法:Linux内核就有这个算法。这里也有一个用户态的实现供参考:github.com/facebook/folly。它的高精度版本能实现微妙级别的定时。下面是一个简单的时间轮定时器的C++实现。原文的代码有问题,不能循环定时,经修改已经支持:


#include <chrono>
#include <functional>
#include <list>
#include <mutex>
#include <thread>
#include <vector>class TimerWheel {
public:using Task = std::function<void()>;explicit TimerWheel(size_t wheel_size, int interval_ms): wheel_size_(wheel_size),interval_ms_(interval_ms),wheel_(wheel_size),current_index_(0) {}~TimerWheel() {Stop();}void Start() {if (running_) {return;}running_ = true;thread_ = std::thread([this]() {while (running_) {std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms_));Tick();}std::cout << "timer oooops!" << std::endl;});thread_.detach();}void Stop() {if (!running_) {return;}running_ = false;if (thread_.joinable()) {thread_.join();}}void AddTask(int timeout_ms, Task task) {std::lock_guard<std::mutex> lock(mutex_);size_t ticks = timeout_ms / interval_ms_;size_t index = (current_index_ + ticks) % wheel_size_;size_t allindex = index;for (size_t i = 1 ; allindex < wheel_size_; i++){allindex = index * i;if (allindex >= wheel_size_)break;wheel_[allindex].push_back(task);}}private:void Tick() {std::lock_guard<std::mutex> lock(mutex_);auto& tasks = wheel_[current_index_];for (const auto& task : tasks) {task();}//tasks.clear();current_index_ = (current_index_ + 1) % wheel_size_;}private:size_t wheel_size_;int interval_ms_;std::vector<std::list<Task>> wheel_;size_t current_index_;bool running_ = false;std::thread thread_;std::mutex mutex_;
};

使用方法:
使用static声明以免被析构,可在cpp类外全局声明,第一个参数为任务容器最大数量,第二个参数为定时判断的毫秒数即最低检测时间单位

static TimerWheel timer(10, 1000);

在要使用的地方,启动并添加任务

timer.Start();
timer.AddTask(2000, []() {std::cout << "Task 1" << std::endl; });
timer.AddTask(3000, []() {std::cout << "Task 2" << std::endl; });

可以在需要的时候停止

timer.Stop();

原文链接:https://blog.csdn.net/sinat_28305511/article/details/131495316

相关文章:

C++ 实现定时器的两种方法(线程定时和时间轮算法修改版)

定时器要求在固定的时间异步执行一个操作&#xff0c;比如boost库中的boost::asio::deadline_timer&#xff0c;以及MFC中的定时器。也可以利用c11的thread, mutex, condition_variable 来实现一个定时器。 1、使用C11中的thread, mutex, condition_variable来实现一个定时器。…...

2023mathorcup大数据竞赛选题建议及思路

大家好呀&#xff0c;昨天6点2023年第四届MathorCup高校数学建模挑战赛——大数据竞赛开赛&#xff0c;在这里给大家带来初步的选题建议及思路。 注意&#xff0c;本文章只是比较简略的图文讲解&#xff0c;更加详细完整的视频讲解请移步&#xff1a; 2023mathorcup大数据数学…...

部署vuepress项目到githubPage

部署vuepress项目到githubPage 1. 项目文件夹下有两个分支&#xff08;main和gh-page&#xff09; 1.1 main分支存放项目代码 1.2 gh-page分支存放 npm run docs:build之后的dist里面的所有文件 2. 分别提交到github上 3. 你的项目/docs/.vuepress/config.js module.export…...

ORACLE表空间说明及操作

ORACLE 表空间作用 数据存储&#xff1a;表空间是数据库中存储数据的逻辑结构。它提供了用于存储表、索引、视图、存储过程等数据库对象的空间。通过划分数据和索引等对象的存储&#xff0c;可以更好地管理和组织数据库的物理存储结构。性能管理和优化&#xff1a;通过将不同类…...

vue使用Element-plus的Image预览时样式崩乱

&#x1f525;博客主页&#xff1a; 破浪前进 &#x1f516;系列专栏&#xff1a; Vue、React、PHP ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 问题&#xff1a; 在使用组件库的image时出现了点小问题&#xff0c;预览的图片层级反而没有表格的层级高 效果图&#xff1a;…...

安装使用vcpkg的简易教程

目录 1. 首先安装vcpkg2. 在vcpkg目录下运行bootstrap-vcpkg.bat 命令3. 接着vs进行集成4. 使用vcpkg搜索可用的包5.下载安装所需包6.下载安装完成 1. 首先安装vcpkg 使用git命令下载 git clone https://github.com/Microsoft/vcpkg.git如果下载失败可直接下载文件 (vcpkg-ma…...

制作一个简单的C语言词法分析程序

1.分析组成 C语言的程序中&#xff0c;有很单词多符号和保留字。一些单词符号还有对应的左线性文法。所以我们需要先做出一个单词字符表&#xff0c;给出对应的识别码&#xff0c;然后跟据对应的表格来写出程序 2.程序设计 程序主要有循环判断构成。不需推理即可产生的符号我…...

Java项目中将MySQL改为8.0以上

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 maven依…...

软考高项-计算题(2)

题4 项目的总预算是包含管理储备的&#xff0c;所以总预算应该是&#xff1a;13238102*360 ETC(BAC-EV)/CPI BAC60 EV60*0.318 CPI18/200.9 ETC42/0.9 答案选择C A 题5 因为题目中提到了“按目前的状况继续发展”&#xff0c;那么是&#xff1a;ETC(BAC-EV)/CPI EV1230*0…...

Centos使用war文件部署jenkins

部署jenkins所需要的jdk环境如下&#xff1a; 这里下载官网最新的版本&#xff1a; 选择jenkins2.414.3版本&#xff0c;所以jdk环境最低得是java11 安装java11环境 这里直接安装open-jdk yum -y install java-11-openjdk.x86_64 java-11-openjdk-devel.x86_64下载jenkins最新…...

数据结构和算法——用C语言实现所有排序算法

文章目录 前言排序算法的基本概念内部排序插入排序直接插入排序折半插入排序希尔排序 交换排序冒泡排序快速排序 选择排序简单选择排序堆排序 归并排序基数排序 外部排序多路归并败者树置换——选择排序最佳归并树 前言 本文所有代码均在仓库中&#xff0c;这是一个完整的由纯…...

吃豆人C语言开发—Day2 需求分析 流程图 原型图

目录 需求分析 流程图 原型图 主菜单&#xff1a; 设置界面&#xff1a; 地图选择&#xff1a; 游戏界面&#xff1a; 收集完成提示&#xff1a; 游戏胜利界面&#xff1a; 游戏失败界面 死亡提示&#xff1a; 这个项目是我和朋友们一起开发的&#xff0c;在此声明一下…...

Nautilus Chain 联合香港数码港举办 BIG DEMO DAY活动,释放何信号?

在今年的 10 月 26 日 9:30-18:30 GMT8 期间&#xff0c;Nautilus Chain 联合香港数码港共同举办了 “BIG DEMO DAY” Web3 项目路演活动&#xff0c;包括Xwinner、Sleek、Tx、All weather、Coral Finance、DBOE、PARSIQ、Hookfi、Parallels、Fintestra 以及 dot.GAMING 等在内…...

手写RPC框架

文章目录 什么是RPC框架RPC框架中的关键点通信协议序列化协议动态代理和反射 目前已有的RPC框架手写RPC框架介绍项目框架项目执行流程项目启动 什么是RPC框架 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;, 简单来说遵循RPC协议的就是RPC框架. …...

音视频常见问题(六):视频黑边或放大

摘要 本文介绍了视频黑边或放大的原因和解决方案。主要原因包括视频分辨率与显示视图尺寸不一致、摄像头采集、美颜滤镜格式兼容和分辨率。为了解决这些问题&#xff0c;开发者可以选择合适的渲染模式、动态调整分辨率、处理视频旋转和使用自定义视频渲染。 即构音视频SDK提供…...

Android笔记(八):基于CameraX库结合Compose和传统视图组件PreviewView实现照相机画面预览和照相功能

CameraX是JetPack库之一&#xff0c;通过CameraX可以向应用增加相机的功能。在下列内容中&#xff0c;将介绍一个结合CameraX实现一个简单的拍照应用。本应用必须采用Android SDK 34。并通过该简单示例&#xff0c;了解传统View层次组件的UI组件如何与Compose组件结合实现移动应…...

【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆

从数量最多的堆取走礼物【LC2558】 给你一个整数数组 gifts &#xff0c;表示各堆礼物的数量。每一秒&#xff0c;你需要执行以下操作&#xff1a; 选择礼物数量最多的那一堆。如果不止一堆都符合礼物数量最多&#xff0c;从中选择任一堆即可。选中的那一堆留下平方根数量的礼物…...

【psychopy】【脑与认知科学】认知过程中的面孔识别加工

目录 实验描述 实验思路 python实现 实验描述 现有的文献认为&#xff0c;人们对倒置的面孔、模糊的面孔等可能会出现加工时长增加、准确率下降的问题&#xff0c;现请你设计一个相关实验&#xff0c;判断不同的面孔是否会出现上述现象。请按照认知科学要求&#xff0c;画…...

File类的常用API

判断文件类型 public boolean isDirectory() public boolean isFile() 获取文件信息 public boolean exists() public String getAbsolutePath() public String getPath() 返回创建文件对象时传入的抽象路径的字符串形式 public String getName() public long lastModi…...

02【Git分支的使用、Git回退、还原】

上一篇&#xff1a;01【Git的基本命令、底层命令、命令原理】 下一篇&#xff1a;03【Git的协同开发、TortoiseGit、IDEA的操作Git】 文章目录 02【Git分支的使用、Git回退、还原】一、分支1.1 分支概述1.1.1 Git分支简介1.1.2 Git分支原理 1.2 创建分支1.2.1 创建普通分支1.…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...