基于时间轮的定时器

原理

图片是一个单层时间轮,当指针走到某一格上,就获取那一格上挂的任务将其执行。

当时如果时间跨度大的时候,格子数明显不够,那么就可以做成多级时间轮。

其实就是当低层的时间轮走了一圈,将它高一层的时间轮走一格,并且将挂在高层时间轮上的任务分配下来。

实现

文件#include"TimeWheel.h"

#include

#include

#include

#include

struct TimeStamp //时间戳

{

int ms;

int s;

int min;

bool operator==(TimeStamp timeStamp)

{

return timeStamp.ms==ms&&timeStamp.s==s&&timeStamp.min==min;

}

};

struct Event //挂在时间槽上的事件

{

std::function call_back;

TimeStamp tri_time; //事件触发的时间

int dur; //多久触发

};

class TimeWheel //时间轮

{

public:

TimeWheel();

~TimeWheel();

void Start(); //启动

int AddTimer(int space,std::function& call_back); //添加定期器

private:

void DoLoop();//主循环

void InsertTimer(Event &event); //插入事件到时间槽

int getMS(const TimeStamp &timeStamp);

void solvingEvents(std::listl); //解决时间槽上的事件

void getNextTime(TimeStamp &nowTimeStamp,int dur); //得到下个时间

private:

std::list *callBackList = nullptr; //当做时间槽上,每一个槽都是一个链表

std::mutex _mutex; //互斥量

TimeStamp timeStamp; //事件轮的时间

int slot_ms; //毫秒的时间槽数量

int slot_s; //秒的时间槽数量

int slot_min; //分的时间槽数量

int step; //最小的间隔时间

};

文件#include"TimeWheel.cpp"

#include"TimeWheel.h"

#include

using namespace std;

TimeWheel::TimeWheel()

{

cout<

timeStamp.ms = timeStamp.s = timeStamp.min = 0;

slot_ms=10;

slot_s=60;

slot_min=60;

step = 100;

callBackList = new list[slot_ms+slot_s+slot_min];

}

TimeWheel::~TimeWheel()

{

delete[] callBackList;

}

void TimeWheel::Start() //开启一个线程

{

cout<

std::thread myThread([&]{

this->DoLoop();

});

myThread.detach();

}

void TimeWheel::DoLoop() //主循环

{

cout<

while(true)

{

this_thread::sleep_for(chrono::milliseconds(step)); //让线程休息step毫秒的时间

unique_lock<:mutex> lock(_mutex);

cout<

TimeStamp per = timeStamp; //per是原来的时间

getNextTime(timeStamp,step); //timeStamp向后走一步

if(per.min!=timeStamp.min) //分针有进位

{

//cout<

list& l = callBackList[slot_ms+slot_s+timeStamp.min];

solvingEvents(l);

l.clear();

}

else if(per.s!=timeStamp.s) //秒针有进位

{

//cout<

list& l = callBackList[slot_ms+timeStamp.s];

solvingEvents(l);

l.clear();

}

else if(per.ms!=timeStamp.ms) //毫秒有进位

{

//cout<

list& l = callBackList[timeStamp.ms];

solvingEvents(l);

l.clear();

}

lock.unlock();

}

}

int TimeWheel::getMS(const TimeStamp &timeStamp) //得到时间戳timeStamp一共多少ms

{

return step * timeStamp.ms + timeStamp.s * 1000 + timeStamp.min * 60 * 1000;

}

void TimeWheel::solvingEvents(listl)

{

for (auto item = l.begin(); item != l.end(); item++)

{

if(timeStamp == item->tri_time) //触发时间到了

{

item->call_back(); //执行函数

//如果需要发生多次加入下面两行

getNextTime(item->tri_time,item->dur);

InsertTimer(*item);

}

else

{

InsertTimer(*item);

}

}

}

void TimeWheel::getNextTime(TimeStamp &nowTimeStamp,int dur)//获得下一个时间

{

int next_ms = getMS(nowTimeStamp)+dur;

nowTimeStamp.min = next_ms/1000/60%slot_min;

nowTimeStamp.s = (next_ms%(1000*60))/1000;

nowTimeStamp.ms = (next_ms%1000)/step;

}

//添加定时器

int TimeWheel::AddTimer(int space,function& call_back)

{

if(space

if(space%step!=0)return -1;

unique_lock<:mutex> lock(_mutex);

Event event;

event.call_back = call_back;

event.tri_time.ms = timeStamp.ms;

event.tri_time.s = timeStamp.s;

event.tri_time.min = timeStamp.min;

event.dur = space;

getNextTime(event.tri_time,event.dur);

//cout<

cout<

InsertTimer(event);

lock.unlock();

return 0;

}

//先时间轮内插入事件

void TimeWheel::InsertTimer(Event &event)

{

if(event.tri_time.min != timeStamp.min) //分钟与现在不同的分钟就插入分的槽

callBackList[slot_ms + slot_s + event.tri_time.min].push_back(event);

else if(event.tri_time.s != timeStamp.s)

callBackList[slot_ms + event.tri_time.s].push_back(event);

else if(event.tri_time.ms != timeStamp.ms)

callBackList[event.tri_time.ms].push_back(event);

}

测试文件Main.cpp

#include

#include

#include"TimeWheel.h"

#include

using namespace std;

void fun100()

{

cout << "------------fun 100--------------" << endl;

}

void fun200()

{

cout << "------------fun 200--------------" << endl;

}

void fun500()

{

cout << "------------fun 500--------------" << endl;

}

void fun1500()

{

cout << "------------fun 1500-------------" << endl;

}

int main()

{

function f100 = std::bind(&fun100);

function f200 = std::bind(&fun200);

function f500 = std::bind(&fun500);

function f1500 = std::bind(&fun1500);

TimeWheel timeWheel;

timeWheel.Start();

//加入定时器

timeWheel.AddTimer(100,f100);

timeWheel.AddTimer(200,f200);

timeWheel.AddTimer(500,f500);

timeWheel.AddTimer(1500,f1500);

while(true){}

return 0;

}

实现效果

java时间轮定时器_基于时间轮的定时器相关推荐

  1. uuid表示时间的部分_基于时间UUID的妙用

    1.jar包获取 https://github.com/cowtowncoder/java-uuid-generator/ com.fasterxml.uuid java-uuid-generator ...

  2. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  3. java线程轮询_基于springboot实现轮询线程自动执行任务

    本文使用: Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行, 但不能在指定 ...

  4. java 长轮询_基于springboot 长轮询的实现操作

    springboot 长轮询实现 基于 @EnableAsync , @Sync @SpringBootApplication @EnableAsync public class DemoApplic ...

  5. java 解析日期格式_日期/时间格式/解析,Java 8样式

    java 解析日期格式 自Java 几乎 开始以来,Java开发人员就通过java.util.Date类(自JDK 1.0起)和java.util.Calendar类(自JDK 1.1起 )来处理日期 ...

  6. monkey 运行时间怎么计算_基于STM32F103C8T6工控板利用定时器计算某段代码的运行时间...

    本人参考了热心网友分享的一些案例,并增加了一些个人认为比较好的想法,重新整合了一下代码. 硬件:某宝网上购买的STM32F103C8T6工控板,价格50¥左右: 思路: 1)利用通用定时器(选择定时器 ...

  7. java网上书店系统_基于JAVA/JSP的网上书店系统

    第一章 JAVA的网络功能与编程 1-1 JAVA语言简介 Java是一种简单易用.完全面向对象.具有平台无关性且安全可靠的主要面向Internet的开发工具.自从1995年正式问世以来,Java的快 ...

  8. mysql基于时间盲注_MYSQL基于时间的盲注详解

    MYSQL基于时间的盲注 联合查询,报错注入,以及布尔盲注,都是基于攻击网站会回显消息,或者将错误信息返回在前端,或者会返回web页面的正确或错误 但是有时候网站关闭了错误回显或过滤了某些关键字,网页 ...

  9. 中西方对时间的差异_中西方时间观念差异_英文

    <中西方时间观念差异_英文>由会员分享,可在线阅读,更多相关<中西方时间观念差异_英文(2页珍藏版)>请在人人文库网上搜索. 1.Compared with America b ...

  10. utc时间 单位换算_一些时间的概念与区分(UTC、GMT、LT、TAI等)

    UT - 世界时 Universal Time 世界时是最早的时间标准.在1884年,国际上将1s确定为全年内每日平均长度的1/8.64×104.以此标准形成的时间系统,称为世界时,即 UT1. 19 ...

最新文章

  1. 浙江大学软件学院2020年保研上机模拟练习 7-3 Partial School Ranking
  2. 部署 DevStack - 每天5分钟玩转 OpenStack(17)
  3. 【安全漏洞】CVE-2021-1732 win32k漏洞分析
  4. 《Splunk智能运维实战》——3.6 制作每一主机不同请求方法数量的图表
  5. 调用微信和支付宝调三方接口扫描二维码?
  6. 中石油训练赛 - Historical Maths(二分)
  7. 如何一次性复制带有markdown/mathjax/latex的博客内容
  8. opensource项目_生日快乐,Opensource.com:9年
  9. 2017.10.28 排序 思考记录
  10. 文件服务器搭建_小型企业文件存储服务器的搭建四部曲
  11. LeetCode Assign Cookies
  12. java四种修饰符_java中的四种修饰符
  13. tsm2812通用定时器中断_通用定时器中断(TIM2)
  14. 在ubuntu安装使用miniconda
  15. MS SqL2000 数据库置疑状态的解决方法[转]
  16. 二叉排序树和二叉平衡树
  17. 笔记本onenote绘画快捷键_怎样设置onenote的快捷键
  18. 《objective-c程序设计》学习笔记
  19. 论本我、自我、超我对人工智能的启示
  20. 京东手机电商大数据统计平台搭建

热门文章

  1. NOPI修改xlsx文件内容,无法正常打开,提示文件格式或文件扩展名无效
  2. b样条和三次样条_B样条(贝塞尔曲线和b样条曲线)
  3. KMeans原理和密度聚类
  4. 有限元计算计算机配置, 有限元分析计算对电脑配置都有什么要求
  5. 自媒体采集平台免费,免费的自媒体采集平台
  6. 安川涂装机器人离线编程_安川机器人离线编程软件
  7. UDS诊断系列介绍03-DCM
  8. 如何解决谷歌浏览器插件屏蔽问题
  9. 黑产的类型与武器库概览
  10. 《统计学》第八版贾俊平第三章课后答案Excel