java实现时间轮定时器_c++ 时间轮定时器实现
前言
之所以写这篇文章,是在一篇博客中看到了时间轮定时器这个东西,感觉很是惊艳,https://www.cnblogs.com/zhongwencool/p/timing_wheel.html。在以前写windows 程序的时候,windows API 自己就实现了SetTimer 这个调用,在超时后会触发OnTimer的回调,然后通过timer_id 调用我们自己事件处理函数,但是在后台开发中,一般都需要自己实现,这里根据博客实现了自己的定时器。
实现
头文件定义TimeWheel.h
/************************************************************************/
/* TimeWheel实现了一个毫秒级别的定时器,最大支持到分钟级别 */
/************************************************************************/
#pragma once
#include
#include
#include
#include
typedef struct TimePos_
{
int ms_pos;
int s_pos;
int min_pos;
}TimePos;
typedef struct EventInfo_
{
int interval;
std::function call_back;
TimePos time_pos;
int timer_id;
}EventInfo;
class TimeWheel
{
public:
TimeWheel();
~TimeWheel();
public:
/*step 以毫秒为单位,表示定时器最小时间粒度
*max_timer 表示定时器所能接受的分钟时间间隔
*/
int InitTimerWheel(int step,int max_min);
int AddTimer(int interval, std::function& call_back);
int DeleteTimer(int timer_id);
private:
int DoLoop();
int GenerateTimerID();
int InsertTimer(int diff_ms,EventInfo& einfo);
int GetNextTrigerPos(int interval,TimePos& time_pos);
int GetMS(TimePos time_pos);
int DealTimeWheeling(std::list leinfo);
private:
std::list *_pCallbackList = nullptr;
std::mutex _mutex;
TimePos _time_pos;
int _lowCount = 0;
int _midCount = 0;
int _highCount = 0;
int _step_ms = 0;
int _timer_count = 0;
};
源文件实现TimerWheel.cpp
#include "TimeWheel.h"
#include
#include
using namespace std;
TimeWheel::TimeWheel()
{
memset(&_time_pos, 0, sizeof(_time_pos));
}
TimeWheel::~TimeWheel()
{
}
int TimeWheel::InitTimerWheel(int step_ms, int max_min)
{
if (1000 % step_ms != 0)
{
cout << "step is not property, should be devided by 1000" << endl;
return -1;
}
int msNeedCount = 1000 / step_ms;
int sNeedCount = 60;
int minNeedCount = max_min;
_pCallbackList = new std::list[msNeedCount + sNeedCount + minNeedCount];
_step_ms = step_ms;
_lowCount = msNeedCount;
_midCount = sNeedCount;
_highCount = minNeedCount;
std::thread th([&]{
this->DoLoop();
});
th.detach();
return 0;
}
int TimeWheel::AddTimer(int interval, std::function& call_back)
{
if (interval < _step_ms || interval % _step_ms != 0 || interval >= _step_ms * _lowCount * _midCount * _highCount)
{
cout << "time interval is invalid" << endl;
return -1;
}
std::unique_lock<:mutex> lock(_mutex);
EventInfo einfo = {0};
einfo.interval = interval;
einfo.call_back = call_back;
einfo.time_pos.ms_pos = _time_pos.ms_pos;
einfo.time_pos.s_pos = _time_pos.s_pos;
einfo.time_pos.min_pos = _time_pos.min_pos;
einfo.timer_id = GenerateTimerID();
InsertTimer(einfo.interval,einfo);
_timer_count++;
cout << "insert timer success time_id: " << einfo.timer_id << endl;
return einfo.timer_id;
}
int TimeWheel::DeleteTimer(int time_id)
{
std::unique_lock<:mutex> lock(_mutex);
int i = 0;
int nCount = _lowCount + _midCount + _highCount;
for (i = 0; i < nCount; i++)
{
std::list& leinfo = _pCallbackList[i];
for (auto item = leinfo.begin(); item != leinfo.end();item++)
{
if (item->timer_id == time_id)
{
item = leinfo.erase(item);
return 0;
}
}
}
if (i == nCount)
{
cout << "timer not found" << endl;
return -1;
}
return 0;
}
int TimeWheel::DoLoop()
{
cout << "........starting loop........" << endl;
static int nCount = 0;
while (true)
{
this_thread::sleep_for(chrono::milliseconds(_step_ms));
std::unique_lock<:mutex> lock(_mutex);
cout << ".........this is " << ++nCount <
TimePos pos = {0};
TimePos last_pos = _time_pos;
GetNextTrigerPos(_step_ms, pos);
_time_pos = pos;
if (pos.min_pos != last_pos.min_pos)
{
list& leinfo = _pCallbackList[_time_pos.min_pos + _midCount + _lowCount];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else if (pos.s_pos != last_pos.s_pos)
{
list& leinfo = _pCallbackList[_time_pos.s_pos + _lowCount];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else if (pos.ms_pos != last_pos.ms_pos)
{
list& leinfo = _pCallbackList[_time_pos.ms_pos];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else
{
cout << "error time not change" << endl;
return -1;
}
lock.unlock();
}
return 0;
}
int TimeWheel::GenerateTimerID()
{
int x = rand() % 0xffffffff;
int cur_time = time(nullptr);
return x | cur_time | _timer_count;
}
int TimeWheel::InsertTimer(int diff_ms,EventInfo &einfo)
{
TimePos time_pos = {0};
GetNextTrigerPos(diff_ms, time_pos);
if (time_pos.min_pos != _time_pos.min_pos)
_pCallbackList[_lowCount + _midCount + time_pos.min_pos].push_back(einfo);
else if (time_pos.s_pos != _time_pos.s_pos)
_pCallbackList[_lowCount + time_pos.s_pos].push_back(einfo);
else if (time_pos.ms_pos != _time_pos.ms_pos)
_pCallbackList[time_pos.ms_pos].push_back(einfo);
return 0;
}
int TimeWheel::GetNextTrigerPos(int interval, TimePos& time_pos)
{
int cur_ms = GetMS(_time_pos);
int future_ms = cur_ms + interval;
time_pos.min_pos = (future_ms / 1000 / 60) % _highCount;
time_pos.s_pos = (future_ms % (1000 * 60)) / 1000;
time_pos.ms_pos = (future_ms % 1000) / _step_ms;
return 0;
}
int TimeWheel::GetMS(TimePos time_pos)
{
return _step_ms * time_pos.ms_pos + time_pos.s_pos * 1000 + time_pos.min_pos * 60 * 1000;
}
int TimeWheel::DealTimeWheeling(std::list leinfo)
{
for (auto item = leinfo.begin(); item != leinfo.end(); item++)
{
int cur_ms = GetMS(_time_pos);
int last_ms = GetMS(item->time_pos);
int diff_ms = (cur_ms - last_ms + (_highCount + 1) * 60 * 1000) % ((_highCount + 1) * 60 * 1000);
if (diff_ms == item->interval)
{
item->call_back();
item->time_pos = _time_pos;
InsertTimer(item->interval, *item);
}
else
{
InsertTimer(item->interval - diff_ms, *item);
}
}
return 0;
}
这里实现的是一个毫秒到分钟级别的三成时间轮定时器。InitTimerWheel 中有两个参数,第一个表示支持的最小时间粒度单位毫秒,第二个参数是支持的最大分钟级别。
时钟原理说明:
1.1. 初始化一个三层时间轮:毫秒刻盘:1000/step_ms 个MSList, 秒刻盘:60个SList, 时刻盘:max_min个MinList;
1.2. MSTick由外界推动,每跳一轮(1000/step_ms格),MSTick复位至0,同时STick跳1格;
1.3. 同理STick每跳一轮(60格),STick复位至0,同时MinTick跳1格;
1.4. 最高层:MinTick跳一轮(max_min格),MinTick复位至0,一个时间轮完整周期完成.
2.事件原理说明:
2.1. 设置时间为TimeOut的事件时,根据TimeOut算出发生此事件时刻的指针位置{TriggerMin,TriggerS,TriggerMS};
2.2. 用{TriggerMin,TriggerS,TriggerMS}与当前指针{NowMin,NowS,NowMS}对比得出事件存放在哪一个指针(Tick);
2.3. 所有层的指针每跳到下一格(Tick01)都会触发格子的事件列表,处理每一个事件Event01:
2.3.1 根据事件Event01的剩余TimeOut算出Event01应该存在上一层(跳得更快)层的位置Pos;
2.3.2 把事件更新到新的Pos(更新TimeOut);
2.3.3 重复处理完Tick01里面所有的事件;
2.3.4 清空Tick01的事件;
2.3.5 最底层(跳最快)层所有的事件遇到指针Tick都会立即执行;
需要指出的是,这里和我所贴的博客中的实现是有点不同的,它所叙述的是一个时分秒级别的定时器,但是我们这里进行了降级,实现的是一个 毫秒,秒,分钟级别的定时器。因为个人感觉,这种级别的定时器使用的概率会更大一些
测试
time_wheel.cpp
#include
#include
#include "TimeWheel.h"
using namespace std;
void fun100()
{
cout << "func 100" << endl;
}
void fun200()
{
cout << "func 200" << endl;
}
void fun500()
{
cout << "func 500" << endl;
}
void fun1500()
{
cout << "func 1500" << endl;
}
void main()
{
std::function f100 = std::bind(&fun100);
std::function f200 = std::bind(&fun200);
std::function f500 = std::bind(&fun500);
std::function f1500 = std::bind(&fun1500);
TimeWheel time_wheel;
time_wheel.InitTimerWheel(100, 5);
int timer1 = time_wheel.AddTimer(100, f100);
int timer2 = time_wheel.AddTimer(200, f200);
int timer3 = time_wheel.AddTimer(500, f500);
//time_wheel.AddTimer(1500, f1500);
bool b = true;
int nLoop = 0;
while (1)
{
nLoop++;
this_thread::sleep_for(chrono::milliseconds(300));
if (b)
{
time_wheel.AddTimer(1500, f1500);
b = false;
}
if (nLoop == 3)
time_wheel.DeleteTimer(timer1);
}
}
结语
java实现时间轮定时器_c++ 时间轮定时器实现相关推荐
- utc时间 单位换算_c++ 时间类型详解 time_t
Unix时间戳(Unix timestamp),或称Unix时间(Unix time).POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00 ...
- java方法里面能改定时器的时间吗_Kafka 时间轮的原理和实现
女主宣言 Kafka 作为一个支持实时处理大量请求的分布式流处理平台,需要一个设计良好的定时器来处理异步任务.本文作者将基于 Kafka 1.1.0 版本的源码来介绍 Kafka 中定时器的基础数据结 ...
- java 时间轮算法_时间轮算法(TimingWheel)是如何实现的?
前言 我在2. SOFAJRaft源码分析-JRaft的定时任务调度器是怎么做的?这篇文章里已经讲解过时间轮算法在JRaft中是怎么应用的,但是我感觉我并没有讲解清楚这个东西,导致看了这篇文章依然和没 ...
- Linux网络编程 | 高性能定时器 :时间轮、时间堆
文章目录 时间轮 时间堆 在上一篇博客中我实现了一个基于排序链表的定时器容器,但是其存在一个缺点--随着定时器越来越多,添加定时器的效率也会越来越低. 而下面的两个高效定时器--时间轮.时间堆,会完美 ...
- 【高性能定时器】 时间轮
时间轮 简述 顾名思义,时间轮就像一个轮子,在转动的时候外界会指向轮子不同的区域,该区域就可以被使用.因此只要将不同时间的定时器按照一定的方法散列到时间轮的不同槽(即时间轮划分的区域)之中,就可以实现 ...
- 分级时间轮优化普通时间轮定时器(2):滴答式分层计时轮
<实现较低的计时器粒度以重传TCP(RTO):时间轮算法如何减少开销> <分级时间轮优化普通时间轮定时器> Table of Contents 描述 新闻 用法 执照 资源 其 ...
- 分级时间轮优化普通时间轮定时器
<实现较低的计时器粒度以重传TCP(RTO):时间轮算法如何减少开销> Table of Contents Ratas-分级计时器轮 (分级)计时器轮 单文件实现,无依赖性 限制单个时间步 ...
- linux现代时间轮算法,linux2.6定时器的时间轮算法分析
1.Overview 常用的定时器实现算法有两种:红黑树和时间轮(timing wheel). 在Linux2.6的代码中,kernel/timer.c文件实现了一个通用定时器机制,使用的是时间轮算法 ...
- linux时间轮算法,关于时间轮的设计 linux hashed Hierarchical timing wheel
参考文章 http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt http://cseweb.ucsd.edu/users/v ...
最新文章
- 联想win10摁F2一直无法进入BIOS
- 【机器学习入门到精通系列】Logistic回归多分类图示
- 【Linux 线程】同一个进程中的线程共享哪些资源
- 多重判定系数怎么求_关于多重共线性
- ueditor 在线附件和在线图片路径错误BUG补丁
- vue多页面开发_使用VUE进行移动端H5页面开发前准备
- python判断英文字母_python判断字符串是否包含字母
- dnf时装预览怎么打开_dnf怎么查找各职业时装代码
- 凤凰系统基于android x x86,凤凰系统X86|Phoenix OS X86 V3.0.8.529官方版
- Java生成简单的验证码图片
- ECharts南丁格尔图
- 【附源码】手写一个Ico生成器
- 未来行业发展趋势分析
- python抓取微博评论破亿_《战狼Ⅱ》破50亿 Python爬虫抓取获取12万条影评分析看它在说...
- js判断是否是微信扫描进入
- ICLR 2022最佳论文解读
- ipad 开源协议_开源iPad替代品,创用CC满12岁,甚至更多
- 文件系统FATFS的移植教程
- python人机交互界面设计_[译]学习IPython进行交互式计算和数据可视化(五)
- openlayers自定义控件 ---仿百度地图指南针
热门文章
- Windows Server 下文件同步
- MX,Y,Z代表力矩 代表什么的力矩
- 自定义表单开发过程及思路笔记
- 基于SCORM标准课件的移动客户端架构设计
- 基于安卓的视频遥控小车——电脑端开发
- MySQL+Navicat安装配置教程(超级详细、保姆级)
- 关于按照Intellij IDEA开发WebService步骤时输入http://localhost:8080/services出现404错误的解决方案
- nginx 代理127.0.0.1的端口
- 清迈中文离线地图App上线
- 请确保dx环境安装正常后进行开播_DX各种问题解决方法汇总