相应的参考链接与注释都在代码里面,不懂的可以直接点开链接查看。
注释:时间轮定时器是指定时间间隔和一轮的总时间进行定时,时间堆定时器是指定执行次数和时间间隔进行定时(不要删除定时器)。
时间轮定时器
TimeWheel.h
#pragma once
#ifndef __TIMEWHEEL_H__
#define __TIMEWHEEL_H__
/*
参考链接
https://cloud.tencent.com/developer/article/1361827
https://www.cnblogs.com/zhongwencool/p/timing_wheel.html
*/
/************************************************************************/
/* TimeWheel实现了一个毫秒级别的定时器,最大支持到分钟级别
进行了修改了,定时器函数,支持接收任意参数,返回类型为void
/************************************************************************/
#include <functional>
#include <list>
#include <thread>
#include <mutex>
typedef struct TimePos_
{
//毫秒,秒,分钟
int ms_pos;
int s_pos;
int min_pos;
}TimePos;
typedef struct EventInfo_
{
//超时时间(为初始化的倍数)
int interval;
//回调函数
std::function<void()> call_back;
//时间
TimePos time_pos;
//定时器ID
int timer_id;
}EventInfo;
class TimeWheel
{
public:
TimeWheel();
~TimeWheel();
public:
/*
step 以毫秒为单位,表示定时器最小时间粒度
max_timer 表示定时器所能接受的分钟时间间隔,表示一轮时间的总分钟数
*/
int InitTimerWheel(int step,int max_min);
//设置时间为TimeOut的事件时,根据TimeOut算出发生此事件时刻的指针位置{TriggerMin,TriggerS,TriggerMS};
template<typename Func, typename... Args>
int AddTimer(int interval, Func&& func, Args&& ... args);
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<EventInfo> leinfo);
private:
//此处不是链表,是链表数组的头指针,时间轮数组
std::list<EventInfo> *_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;
};
//增加计时器
/*
interval必须是_step_ms的倍数
*/
template<typename Func, typename... Args>
int TimeWheel::AddTimer(int interval, Func&& func, Args&& ... args)
{
if (interval < _step_ms || interval % _step_ms != 0 || interval >= _step_ms * _lowCount * _midCount * _highCount)
{
//std::cout << "time interval is invalid" << std::endl;
return -1;
}
std::unique_lock<std::mutex> lock(_mutex);
EventInfo einfo = { 0 };
einfo.interval = interval;
einfo.call_back = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);;
//初始化事件的时间
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;
//随机生成id
einfo.timer_id = GenerateTimerID();
//插入定时器,定时器个数加一,返回定时器id
InsertTimer(einfo.interval, einfo);
_timer_count++;
//std::cout << "insert timer success time_id: " << einfo.timer_id << std::endl;
return einfo.timer_id;
}
#endif //__TIMEWHEEL_H__
TimeWheel.cpp
#include "TimeWheel.h"
#include <iostream>
#include <windows.h>
#include <ctime>
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)
{
//std::cout << "step is not property, should be devided by 1000" << std::endl;
return -1;
}
//毫秒,秒,分钟。
int msNeedCount = 1000 / step_ms;
int sNeedCount = 60;
int minNeedCount = max_min;
//事件
//初始化链表的数组,数组里的元素为链表,时间轮数组
_pCallbackList = new std::list<EventInfo>[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<void(void)>& call_back)
//{
// if (interval < _step_ms || interval % _step_ms !=0 || interval >= _step_ms * _lowCount * _midCount * _highCount)
// {
// //std::cout << "time interval is invalid" << std::endl;
// return -1;
// }
//
// std::unique_lock<std::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;
// //随机生成id
// einfo.timer_id = GenerateTimerID();
//
// //插入定时器,定时器个数加一,返回定时器id
// InsertTimer(einfo.interval, einfo);
// _timer_count++;
//
// //std::cout << "insert timer success time_id: " << einfo.timer_id << std::endl;
// return einfo.timer_id;
//
//}
//删除定时器
int TimeWheel::DeleteTimer(int timer_id)
{
std::unique_lock<std::mutex> lock(_mutex);
int i = 0;
//最大事件个数
int nCount = _lowCount + _midCount + _highCount;
for (i = 0; i < nCount; i++)
{
std::list<EventInfo>& leinfo = _pCallbackList[i];
for (auto item = leinfo.begin(); item != leinfo.end(); item++)
{
if (item->timer_id == timer_id)
{
item = leinfo.erase(item);
return 0;
}
}
}
if (i == nCount)
{
//std::cout << "timer not found" << std::endl;
return -1;
}
return 0;
}
int TimeWheel::DoLoop()
{
//std::cout << "........starting loop........" << std::endl;
static int nCount = 0;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(_step_ms));
std::unique_lock<std::mutex> lock(_mutex);
//std::cout << ".........this is " << ++nCount << " loop........." << std::endl;
TimePos pos = { 0 };
TimePos last_pos = _time_pos;
GetNextTrigerPos(_step_ms, pos);
_time_pos = pos;
if (pos.min_pos != last_pos.min_pos)
{
std::list<EventInfo>& leinfo = _pCallbackList[_time_pos.min_pos + _midCount + _lowCount];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else if (pos.s_pos != last_pos.s_pos)
{
std::list<EventInfo>& leinfo = _pCallbackList[_time_pos.s_pos + _lowCount];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else if (pos.ms_pos != last_pos.ms_pos)
{
std::list<EventInfo>& leinfo = _pCallbackList[_time_pos.ms_pos];
DealTimeWheeling(leinfo);
leinfo.clear();
}
else
{
//std::cout << "error time not change" << std::endl;
return -1;
}
lock.unlock();
}
return 0;
}
//生成ID
int TimeWheel::GenerateTimerID()
{
srand((int)time(0));
int x = rand() % 0xffffffff;
int cur_time = static_cast<int>(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);
//数组的每一个元素都是一个list链表
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<EventInfo> 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;
}
测试
example.cpp
#include <iostream>
#include <functional>
#include <string>
#include "TimeWheel.h"
using namespace std;
int g_count=0;
void fun100(string s)
{
g_count++;
cout << s<<" "<<g_count << endl;
}
void fun200()
{
cout << "func 200" << endl;
}
void fun500()
{
cout << "func 500" << endl;
}
void fun1500()
{
cout << "func 1500" << endl;
}
void main()
{
/*std::function<void()> f100 = std::bind(&fun100);
std::function<void()> f200 = std::bind(&fun200);
std::function<void()> f500 = std::bind(&fun500);
std::function<void()> f1500 = std::bind(&fun1500);*/
TimeWheel time_wheel;
time_wheel.InitTimerWheel(1000, 5);
int timer1 = time_wheel.AddTimer(1000, fun100,"时间轮");
//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);
}
*/
system("pause");
return;
}
时间堆定时器
锁文件 critical.h
#pragma once
#ifndef __CRITICAL_H__
#define __CRITICAL_H__
#include <Windows.h>
namespace raii
{
class critical
{
private:
CRITICAL_SECTION* _crit;
public:
critical(CRITICAL_SECTION* crit);
critical(const critical&) = delete;
critical& operator =(const critical&) = delete;
~critical();
};
inline critical::critical(CRITICAL_SECTION* crit)
{
_crit = crit;
//进入临界区
EnterCriticalSection(_crit);
}
inline critical::~critical()
{
//离开临界区
LeaveCriticalSection(_crit);
}
}
#endif //__CRITICAL_H__
time_heap.h
#pragma once
#ifndef __TIME_HEAP_H__
#define __TIME_HEAP_H__
/*
参考链接
https://blog.csdn.net/qq_28398301/article/details/105015492
*/
#include <future>
#include <functional>
//c++17
#include <type_traits>
#include "critical.h"
class time_heap
{
private:
// 事件信息
class event
{
friend class time_heap;
private:
intptr_t _origin; //源地址
uint64_t _ms; //定时时长(按秒计算,可以是小数)
uint32_t _count; //执行数
std::function<void()> _func; //回调函数
protected:
public:
event(intptr_t origin_, uint64_t ms_, uint32_t count_, std::function<void()>&& func_);
event(const event&) = delete;
event& operator =(const event&) = delete;
~event() = default;
// 删除函数
void del();
};
// 返回数据
template <class T>
class result_data
{
friend class time_heap;
private:
event* _info; //事件信息
std::shared_ptr<std::packaged_task<T()>> _pack_func; //已包装的函数
protected:
public:
bool valid; //有效性
uint32_t count; //执行数
result_data(uint32_t count_, std::shared_ptr<std::packaged_task<T()>> pack_func_);
result_data(const result_data&) = delete;
result_data& operator =(const result_data&) = delete;
~result_data() = default;
// 获取执行结果
T get();
// 删除定时器
void del();
};
// 堆节点
struct node
{
uint64_t ms; //结束时间
event* info;
node() = default;
node(const node&) = delete;
node(node&& that_);
node& operator =(const node& that_);
node& operator =(node&& that_);
~node() = default;
};
std::atomic<bool> _death; //结束
CRITICAL_SECTION _cri; //临界区
node* _heap; //最小堆
uint32_t _max_size; //最大存储数
uint32_t _size; //存储数
uint64_t _event_time; //插入时间
HANDLE _event; //事件
static std::unique_ptr<time_heap> _instance; //实例指针
// 添加节点
void add_node();
// 删除节点
void del_node(uint32_t index_);
// 删除指定下标定时器
void del_timer(uint32_t index_);
// 重置定时器
void reset_timer(uint32_t index_);
// 扩容
void expansion();
protected:
public:
time_heap(uint32_t max_size_ = 64);
~time_heap();
// 单例
static time_heap& instance();
// 获取距当前时间(毫秒)
uint64_t get_ms();
// 添加
template<typename Func, typename... Args>
auto add(double second_, uint32_t count_, Func&& func_, Args&& ... args_);
};
//事件构造函数
inline time_heap::event::event(intptr_t origin_, uint64_t ms_, uint32_t count_, std::function<void()>&& func_) :
_origin(origin_),
_ms(ms_),
_count(count_),
_func(std::move(func_))
{};
//事件删除函数
inline void time_heap::event::del()
{
auto timer = &time_heap::instance();
raii::critical r1(&timer->_cri);
//定时器ID
/*
强制类型转换
参考
https://blog.csdn.net/u014786409/article/details/93751093
*/
uint32_t index = static_cast<uint32_t>((_origin - reinterpret_cast<intptr_t>(&timer->_heap[1].ms)) / sizeof(node) + 1);
timer->del_timer(index);
}
//返回结果构造函数
template <class T>
inline time_heap::result_data<T>::result_data(uint32_t count_, std::shared_ptr<std::packaged_task<T()>> pack_func_) :
_info(nullptr),
_pack_func(pack_func_),
//有效性为真
valid(true),
count(count_)
{}
//返回结果:得到结果
template <class T>
inline T time_heap::result_data<T>::get()
{
return _pack_func->get_future().get();
}
//返回结果:删除函数
template <class T>
void time_heap::result_data<T>::del()
{
if (valid) {
//将有效性置为假,删除事件
valid = false;
_info->del();
return;
}
}
/*
堆:复制构造函数
&&右值引用(临时变量)
参考
https://blog.csdn.net/kitekitebaby/article/details/72566145
*/
inline time_heap::node::node(node&& that_)
{
memcpy_s(this, sizeof(node), &that_, sizeof(node));
this->info->_origin = reinterpret_cast<intptr_t>(&this->info);
//将that置为0
memset(&that_, 0, sizeof(node));
}
/*
堆:重载=
*/
inline time_heap::node& time_heap::node::operator =(const node& that_)
{
if (&that_ == this) {
return *this;
}
memcpy_s(this, sizeof(node), &that_, sizeof(node));
this->info->_origin = reinterpret_cast<intptr_t>(&this->info);
return *this;
}
/*
堆:重载=
*/
inline time_heap::node& time_heap::node::operator =(node&& that_)
{
if (&that_ == this) {
return *this;
}
memcpy_s(this, sizeof(node), &that_, sizeof(node));
this->info->_origin = reinterpret_cast<intptr_t>(&this->info);
memset(&that_, 0, sizeof(node));
return *this;
}
/*
时间堆:删除定时器
*/
inline void time_heap::del_timer(uint32_t index_)
{
raii::critical r1(&_cri);
if (_size < index_) {
return;
}
//从堆里面删除index的事件和节点
delete _heap[index_].info;
del_node(index_);
}
/*
重置定时器;
将节点事件复制,定时时长更新。去掉老的,增加新的
*/
inline void time_heap::reset_timer(uint32_t index_)
{
raii::critical r1(&_cri);
auto timer = std::move(_heap[index_]);
//现在的时间+事件的定时时长,按秒计算
timer.ms = get_ms() + timer.info->_ms * 1000; //结束时间
del_node(index_);
_heap[_size + 1] = std::move(timer);
add_node();
}
/*
获取时间
https://blog.csdn.net/qq_31175231/article/details/77923212
*/
inline uint64_t time_heap::get_ms()
{
//返回当前时间距1970-1-1 的毫秒数
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
template<typename Func, typename... Args>
auto time_heap::add(double second_, uint32_t count_, Func&& func_, Args&&... args_)
{
raii::critical r1(&_cri);
auto current_size = _size + 1;
if (current_size == _max_size) {
expansion();
}
//c++11
typedef typename std::result_of<Func(Args...)>::type re_t;
//c++17
//using re_t = typename std::invoke_result<Func, Args...>::type; //回调函数返回类型
//typedef typename std::invoke_result<Func, Args...>::type re_t;
auto task = std::make_shared<std::packaged_task<re_t()>>(std::bind(std::forward<Func>(func_), std::forward<Args>(args_)...)); //已包装回调函数指针
std::shared_ptr<result_data<re_t>> result = std::make_shared<result_data<re_t>>(count_, task);//返回数据
uint64_t mini_time = _heap[1].ms;//最小时间
// 添加节点(添加事件,事件结束时间)
_heap[current_size].ms = get_ms() + static_cast<int64_t>(second_) * 1000; //结束时间
_heap[current_size].info = new event(reinterpret_cast<intptr_t>(&_heap[current_size].ms), static_cast<uint64_t>(second_), count_, [=]()
{
(*task)();
if (--result->count == 0)
{
result->valid = false;
}
else
{
task->reset();
}
}
);
result->_info = _heap[current_size].info;
add_node();
// 决定是否唤醒
if (mini_time != _heap[current_size].ms) {
SetEvent(_event);
_event_time = get_ms();
}
return result;
}
#endif //__TIME_HEAP_H__
time_heap.cpp
#include "time_heap.h"
std::unique_ptr<time_heap> time_heap::_instance;
time_heap::time_heap(uint32_t max_size_) :
_death(false),
_heap(new node[max_size_]{}),
_max_size(max_size_),
_size(0),
_event(CreateEvent(NULL, FALSE, FALSE, NULL))
{
// 初始化临界区
InitializeCriticalSection(&_cri);
std::thread work_thread([&]
{
DWORD wait_re, ms = INFINITE;
std::shared_ptr<std::function<void()>> func;
while (true) {
wait_re = ms ? WaitForSingleObject(_event, ms) : WAIT_TIMEOUT;
if (!_size) {
ms = INFINITE;
continue;
}
if (_death) {
break;
}
auto current_ms = get_ms();
raii::critical r1(&_cri);
if (wait_re == WAIT_OBJECT_0) { //事件
ms = static_cast<DWORD>(current_ms > _heap[1].ms ? 0 : (_heap[1].ms - current_ms - (current_ms - _event_time)));
}
else if (wait_re == WAIT_TIMEOUT)
{ //超时
//printf("超时\n");
_heap[1].info->_func();
if (_heap[1].info->_count == INFINITE)
{
reset_timer(1);
}
else if (--_heap[1].info->_count == 0)
{
del_timer(1);
}
else {
reset_timer(1);
}
ms = static_cast<DWORD>(_size > 0 ? _heap[1].ms - current_ms : INFINITE);
}
else if (wait_re == WAIT_FAILED) { //失败
printf("失败: %I64d\n", current_ms);
}
}
});
work_thread.detach();
}
time_heap::~time_heap()
{
_death = true;
{
raii::critical r1(&_cri);
// 退出工作线程
SetEvent(_event);
for (; _size > 0; --_size) {
delete _heap[_size].info;
}
delete[] _heap;
}
DeleteCriticalSection(&_cri);
}
void time_heap::add_node()
{
raii::critical r1(&_cri);
uint32_t index1 = ++_size, index2 = index1 >> 1;
while (index1 > 1 && _heap[index2].ms > _heap[index1].ms) {
std::swap(_heap[index1], _heap[index2]);
index1 = index2;
index2 >>= 1;
}
}
/*
堆排序
参考链接
https://blog.csdn.net/wangrenhaioylj/article/details/108565134
*/
void time_heap::del_node(uint32_t index_)
{
raii::critical r1(&_cri);
if (_size < index_)
{
return;
}
// 向下调整
if (_heap[_size].ms > _heap[index_].ms)
{
uint32_t index1 = index_, index2 = index1 << 1;
while (index2 < _size)
{
if (_heap[index2].ms > _heap[index2 + 1].ms)
{
++index2;
}
if (_heap[_size].ms > _heap[index2].ms)
{
_heap[index1] = _heap[index2];
index1 = index2;
index2 <<= 1;
}
else
{
break;
}
}
_heap[index1] = _heap[_size];
memset(&_heap[_size], 0, sizeof(node));
}
// 向上调整
else if (_heap[_size].ms < _heap[index_].ms)
{
uint32_t index1 = index_ >> 1, index2 = _size;
while (_heap[index1].ms > _heap[index2].ms)
{
std::swap(_heap[index1], _heap[_size]);
index2 = index1;
index1 >>= 1;
}
_heap[index_] = _heap[_size];
memset(&_heap[_size], 0, sizeof(node));
}
// 不做调整
else
{
_heap[index_] = _heap[_size];
memset(&_heap[_size], 0, sizeof(node));
}
if (--_size > 0)
{
_event_time = get_ms();
SetEvent(_event);
}
}
void time_heap::expansion()
{
auto size = sizeof(node) * _max_size;
node* new_heap = new node[_max_size <<= 1]{};
raii::critical r1(&_cri);
memcpy_s(new_heap, size << 1, _heap, size);
delete[] _heap;
_heap = new_heap;
}
/*
参考
https://blog.csdn.net/ynshi57/article/details/108083019
https://www.cnblogs.com/xuhuajie/p/11647164.html
*/
time_heap& time_heap::instance()
{
static std::once_flag s_flag;
std::call_once(s_flag, [&]()
{
_instance.reset(new time_heap);
}
);
return *_instance;
}
使用example.cpp
#include "time_heap.h"
/*
使用说明:
在删除定时器之前(务必不要删除,否则只执行一次)
初始化
auto &timer = time_heap::instance();
加入定时器,参数:秒(可以填小数,转换为毫秒),指定执行次数,函数,函数的参数。
auto timer1 = timer.add(second, count,test_1, g_index);
//得到返回结果,返回为void的 不需要执行,否则出错
if (timer1->valid) {
auto result = timer1->get();
}
删除
timer1->del();
*/
int g_index = 0;
int test_1(int index)
{
g_index++;
printf("%d\n", g_index);
return 0;
}
void main()
{
auto &timer = time_heap::instance();
//定时时长(单位:秒,由于是double可以传入0.05这样的数字,会自动转为毫秒)
double second = 0.001;
//执行次数
uint32_t count = 1001;
//timer.add函数的返回值是一个std::shared_ptr对象。不用手动销毁
//auto timer1 = timer.add(second, count, [&](int index) {
// printf("%d\n",index);
// return index;
//}
//, 7); //不定参,可以使用任意类型个数的参数
auto timer1 = timer.add(second, count,test_1, g_index);
//获取事件函数返回值(若未事件未执行完成将堵塞)
//auto result = timer1->get();
//安全的获取事件函数返回值(若未事件未执行完成将堵塞,超过count次get完成后再次get将cash)
/*
返回是void的话,不需要执行。
*/
if (timer1->valid) {
auto result = timer1->get();
}
//printf("%d\n", result);
//timer1->del(); //删除定时事件
//system("pause");
getchar();
return;
}