当前位置: 首页 > 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

http://www.lryc.cn/news/209490.html

相关文章:

  • 2023mathorcup大数据竞赛选题建议及思路
  • 部署vuepress项目到githubPage
  • ORACLE表空间说明及操作
  • vue使用Element-plus的Image预览时样式崩乱
  • 安装使用vcpkg的简易教程
  • 制作一个简单的C语言词法分析程序
  • Java项目中将MySQL改为8.0以上
  • 软考高项-计算题(2)
  • Centos使用war文件部署jenkins
  • 数据结构和算法——用C语言实现所有排序算法
  • 吃豆人C语言开发—Day2 需求分析 流程图 原型图
  • Nautilus Chain 联合香港数码港举办 BIG DEMO DAY活动,释放何信号?
  • 手写RPC框架
  • 音视频常见问题(六):视频黑边或放大
  • Android笔记(八):基于CameraX库结合Compose和传统视图组件PreviewView实现照相机画面预览和照相功能
  • 【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆
  • 【psychopy】【脑与认知科学】认知过程中的面孔识别加工
  • File类的常用API
  • 02【Git分支的使用、Git回退、还原】
  • Qt文件 I/O 操作
  • Springboot 使用JavaMailSender发送邮件 + Excel附件
  • 软件工程——期末复习知识点汇总
  • postgresSQL 数据库本地创建表空间读取本地备份tar文件与SQL文件
  • Elasticsearch跨集群检索配置
  • 第九章 软件BUG和管理
  • 大厂面试题-Java并发编程基础篇(二)
  • 测绘屠夫报表系统V1.0.0-beta
  • 『力扣刷题本』:移除链表元素
  • 图像特征Vol.1:计算机视觉特征度量|第一弹:【纹理区域特征】
  • day01:数据库DDL