C++定时器的实现之格式修订版

个人认为一个完备的定时器需要有如下功能:

  • 在某一时间点执行某一任务

  • 在某段时间后执行某一任务

  • 重复执行某一任务N次,任务间隔时间T

那么如何实现定时器呢?下面是我自己实现的定时器逻辑,源码链接最后会附上。

定时器中主要的数据结构

  • 优先级任务队列:队列中存储任务,每个任务会添加时间戳,最近的时间戳的任务会先出队。

  • 锁和条件变量:当有任务需要执行时,用于通知正在等待的线程从任务队列中取出任务执行。

  • 线程池:各个任务会放在线程池中执行。

下面是相关代码:

class TimerQueue {public:  struct InternalS {      std::chrono::time_point<std::chrono::high_resolution_clock> time_point_;      std::function<void()> func_;      bool operator<(const InternalS& b) const { return time_point_ > b.time_point_; }  };  enum class RepeatedIdState { kInit = 0, kRunning = 1, kStop = 2 };
private:  std::priority_queuequeue_;  bool running_ = false;  std::mutex mutex_;  std::condition_variable cond_;wzq::ThreadPool thread_pool_;std::atomic<int> repeated_func_id_;  wzq::ThreadSafeMap<int, RepeatedIdState> repeated_id_state_map_;};

如何开启定时器功能

打开内部的线程池功能,用于执行放入定时器中的任务,同时新开一个线程,循环等待任务到来后送入线程池中执行。

bool Run() {    bool ret = thread_pool_.Start();    if (!ret) {        return false;    }    std::thread([this]() { RunLocal(); }).detach();    return true;}
void RunLocal() {    while (running_) {        std::unique_lock<std::mutex> lock(mutex_);        if (queue_.empty()) {            cond_.wait(lock);            continue;        }        auto s = queue_.top();        auto diff = s.time_point_ - std::chrono::high_resolution_clock::now();        if (std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() > 0) {            cond_.wait_for(lock, diff);            continue;        } else {            queue_.pop();            lock.unlock();            thread_pool_.Run(std::move(s.func_));        }    }}

如何在某一时间点执行任务

根据时间戳构造InternalS,放入队列中:

template <typename F, typename... Args>
void AddFuncAtTimePoint(const std::chrono::time_point<std::chrono::high_resolution_clock>& time_point, F&& f,                        Args&&... args) {    InternalS s;    s.time_point_ = time_point;    s.func_ = std::bind(std::forward(f), std::forward(args)...);    std::unique_lock<std::mutex> lock(mutex_);    queue_.push(s);    cond_.notify_all();}

如何循环执行任务

首先为这个循环任务生成标识ID,外部可以通过ID来取消此任务继续执行,代码如下,内部以类似递归的方式循环执行任务。

template <typename R, typename P, typename F, typename... Args>int AddRepeatedFunc(int repeat_num, const std::chrono::duration& time, F&& f, Args&&... args) {    int id = GetNextRepeatedFuncId();    repeated_id_state_map_.Emplace(id, RepeatedIdState::kRunning);    auto tem_func = std::bind(std::forward(f), std::forward(args)...);    AddRepeatedFuncLocal(repeat_num - 1, time, id, std::move(tem_func));    return id;}
int GetNextRepeatedFuncId() { return repeated_func_id_++; }
template <typename R, typename P, typename F>void AddRepeatedFuncLocal(int repeat_num, const std::chrono::duration& time, int id, F&& f) {    if (!this->repeated_id_state_map_.IsKeyExist(id)) {        return;    }    InternalS s;    s.time_point_ = std::chrono::high_resolution_clock::now() + time;    auto tem_func = std::move(f);    s.repeated_id = id;    s.func_ = [this, &tem_func, repeat_num, time, id]() {        tem_func();        if (!this->repeated_id_state_map_.IsKeyExist(id) || repeat_num == 0) {            return;        }        AddRepeatedFuncLocal(repeat_num - 1, time, id, std::move(tem_func));    };    std::unique_lock<std::mutex> lock(mutex_);    queue_.push(s);    lock.unlock();    cond_.notify_all();}

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338616.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 性能调优_Java性能调优调查结果(第四部分)

java 性能调优这是本系列中的最后一篇文章&#xff0c;我们将分析我们在2014年10月进行的Java Performance Tuning Survey的结果。如果您尚未阅读第一篇文章&#xff0c;建议您首先阅读以下内容&#xff1a; 性能问题的频率和严重性 最受欢迎的监控解决方案 查找根本原因的工…

Android接入热敏打印机,Android 关于佳博和汉印蓝牙热敏打印机开发

接上篇文章Android之BLE(低功耗)蓝牙开发&#xff0c;本篇文章针对上篇博文中提出的两款打印机的开发流程进行记录。首先不管时佳博打印机还是汉印打印机&#xff0c;都是先对他们各自的lib进行导入&#xff0c;如图&#xff1a;导入lib之后&#xff0c;一定要记得进行sync pro…

C 桥接模式 - 开关和电器

桥接模式&#xff08;Bridge Pattern&#xff09;是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。1模式结构UML 结构图&#xff1a;Abstraction&#xff08;抽象类&#xff09;&#xff1a;用于定义抽象类的接口&#xff0c;并且维护一个指向 Implementor…

centos8配置本地光盘yum源_CentOS8 配置本地yum源的详细教程

centos8发行版通过 baseos 和应用流 (appstream) 仓库发布&#xff0c;appstream 是对传统 rpm 格式的全新扩展&#xff0c;为一个组件同时提供多个主要版本centos8 自带封装了nginx&#xff0c;这篇文章给大家介绍centos8 配置本地yum源&#xff0c;具体内容如下所示&#xff…

javafx显示image_如何摆脱JavaFX中的重点突出显示

javafx显示image今天&#xff0c;有人问我是否知道摆脱JavaFX控件&#xff08;分别是按钮&#xff09;的焦点突出的方法&#xff1a; 有关此问题的大多数文章和提示建议添加&#xff1a; .button:focused {-fx-focus-color: transparent; }但是使用这种样式&#xff0c;仍然…

android aop静态方法,spring aop 不能对静态方法进行增强解决

想要通过aop的方式记录HttpUtils发出的post请求日志&#xff0c;但是 aop 不能对静态方法进行增强。只能对实例方法进行增强。。如果一定要增强静态方法&#xff0c;我们可以对目标类使用单例模式&#xff0c;然后通过调用实例方法去调用那个静态方法&#xff0c;而且对应的对象…

汉字笔画动图怎么做_隶书基本笔画教程(动态图)

隶书开创并奠定了汉字的书写形式。而隶书的美时而古朴遒劲&#xff0c;时而秀美温润&#xff0c;实在是令人神往。笔法有方有圆&#xff0c;方圆并用。下面文章以明朗的笔迹演示&#xff0c;结合相对切实的例字&#xff0c;给大家详尽讲解隶书的基本写法。掌握这些基本写法后&a…

C语言没有引用,只有指针

这个问题是昨晚上有同学在知识星球提问&#xff0c;但是因为前两天一直在出差&#xff0c;比较累&#xff0c;没认真回答&#xff0c;今天打球回来&#xff0c;就把这个事情解决了。我想说的已经在题目说明的很清楚了&#xff0c;C语言是没有引用的&#xff0c;引用是在C 里面才…

java日志使用_使用Java 8防止日志过宽

java日志使用一些日志将被机器消耗并永久保存。 其他日志仅用于调试和供人类使用。 在后一种情况下&#xff0c;您通常要确保您不会产生太多的日志&#xff0c;尤其是不会产生太宽的日志&#xff0c;因为一旦行长超过一定大小&#xff08; 例如&#xff0c;此Eclipse bug &…

android 磁场传感器 罗盘,HMC5883L电子指南针罗盘模块 GY-271三轴磁场传感器 的相关教程 带Arduino 51源代码...

//***************************************// HMC5883 51串口测试程序// 使用单片机STC89C51// 晶振&#xff1a;11.0592M// 显示&#xff1a;PC串口// 编译环境 Keil uVision2// 参考宏晶网站24c04通信程序// 时间&#xff1a;2011年3月1日//*******************************…

python如何实现人工智能应用锁_如何清除应用锁的数据库

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航&#xff0c;为用户…

C/C 代码规范注释有哪些讲究?

如果领导给你一个项目的源码让你阅读&#xff0c;并理解重构代码&#xff0c;但里面一句注释都没有&#xff0c;我想这肯定是之前同事“删库跑路”了。看一份源码什么很重要&#xff1f;除了各种代码规范之外&#xff0c;还有一个比较重要的就是注释。注释虽然写起来很痛苦, 但…

记忆化搜索 递归缓存_需要微缓存吗? 营救记忆

记忆化搜索 递归缓存缓存解决了各种各样的性能问题。 有很多方法可以将缓存集成到我们的应用程序中。 例如&#xff0c;当我们使用Spring时&#xff0c;可以轻松使用Cacheable支持。 非常简单&#xff0c;但我们仍然必须配置缓存管理器&#xff0c;缓存区域等。有时&#xff0c…

qq互联android sdk,qq互联.Android

导读&#xff1a;2.2调用示例&#xff0c;这里以发送文字微博接口的调用为例例&#xff0c;来说明通过requestAsync调用兼容接口的方法&#xff1a;&#xff0c;在上面的调用中&#xff0c;调用获取用户信息接口的示例代码如下&#xff1a;&#xff0c;调用发送带图微博接口的&…

go语音protobuf_golang 使用 protobuf 的教程

1、下载protobuf的编译器protoc地址&#xff1a;window&#xff1a;下载: protoc-3.3.0-win32.zip解压&#xff0c;把bin目录下的protoc.exe复制到GOPATH/bin下&#xff0c;GOPATH/bin加入环境变量。当然也可放在其他目录&#xff0c;需加入环境变量&#xff0c;能让系统找到pr…

C 流插入和流提取运算符的重载

<<运算符的重载C 在输出内容时&#xff0c;最常用的方式&#xff1a;std::cout << 1 <<"hello";提出问题&#xff1a;那这条语句为什么能成立呢&#xff1f;cout 是什么&#xff1f;为什么 << 运算符能用在 cout 上呢&#xff1f;原因&#…

primefaces_使用Bean验证扩展PrimeFaces CSV

primefaces你们中有些人已经知道我和我的合著者Mertalışkan正在研究PrimeFaces Cookbook的2.版。 Packt Publishing允许我从新章节“客户端验证”的一个食谱中摘录一小部分摘录。 这将有助于使读者知道这本书的内容。 在此博客文章中&#xff0c;我想讨论使用Bean验证扩展的P…

android math类,GitHub - Zihin/MathModeling-Android

MathModeling-Android项目背景说明与数学建模有关的基于Android平台的手机应用软件&#xff0c;面向全体人员提供数学建模相关服务&#xff0c;开发人员均为东北大学软件学院本科学生&#xff0c;开发时间为两个月。基本功能实现如下功能&#xff0c;满足同学们在数学建模学习上…

guid主键 oracle_使用GUID作为数据库主键的测试

今天听了MSDN的WebCast&#xff0c;是关于Entlib的数据访问的讲座&#xff0c;末尾我问了两个自己所关心的问题&#xff1a;在一个较大型的应用中&#xff0c;如果需要用到两套以上的数据库(如&#xff1a;SQL Server和Oracle)&#xff0c;是否可以把需要的sql查询全部封装在存…

函数指针,指针函数,函数指针数组

这是一个群友发的笔试题目&#xff0c;里面涉及的东西也比较有意思。直接看代码void (*f[])(char *)这个是个什么东西&#xff1f;我们先看看下面的东西函数指针和指针函数的定义我们看个代码int *func(int a,int b)我们之前说过运算符的优先级&#xff0c;「 * 」 的优先级低…