#pragma once #include <stdint.h> #include <mutex> #include <list> #include <atomic> #include <vector>
#define CountArrar(arr) (sizeof(arr)/sizeof(arr[0]))
class TimeWheel { private: struct TimerEvent{ uint16_t server_id_; clock_t interval_; clock_t nxt_trigger_time_; void(*call_back_)(void* data); void* data_; uint32_t timer_id_; int repeat_; }; typedef std::list<TimerEvent*> list_timer_event; public: const static int s_arr_timer_count = 4; static TimeWheel* get_instance(){ return &s_instance; }
void init(); bool run_sink(); uint32_t add_timer(uint16_t server_id, int interval, void(*call_back)(void*), void* data, int repeat = 1); bool delete_timer(uint32_t timer_id); private: TimeWheel() {} TimeWheel(const TimeWheel&) {} ~TimeWheel();
void add(TimerEvent* timer_event); inline TimerEvent* create_timer(); inline void release_timer(TimerEvent* timer_event);
static TimeWheel s_instance; const static int s_arr_timer[s_arr_timer_count - 1]; private: bool running_; std::atomic<uint32_t> cur_time_id_;
clock_t cur_clock_;
clock_t nxt_clock_[s_arr_timer_count - 1]; list_timer_event timer_type_[s_arr_timer_count]; list_timer_event timer_storage_; list_timer_event timer_all_; std::mutex timer_mutex_; };
///
#include "TimeWheel.h" #include<thread> #include <ctime>
TimeWheel TimeWheel::s_instance; const int TimeWheel::s_arr_timer[s_arr_timer_count - 1] = { 1000, 60 * 1000, 60 * 60 * 1000 };
TimeWheel::~TimeWheel(){ for (auto it : timer_all_){ delete it; } timer_all_.clear(); timer_storage_.clear(); for (int i = 0; i < s_arr_timer_count; i++){ timer_type_[i].clear(); } }
void TimeWheel::init(){ clock_t clock = static_cast<clock_t> (std::clock() * 1000 / CLOCKS_PER_SEC);
for (int i = 0; i < CountArrar(nxt_clock_); i++){ nxt_clock_[i] = clock + s_arr_timer[i]; } }
bool TimeWheel::run_sink(){ std::this_thread::sleep_for(std::chrono::milliseconds(20));
std::unique_lock<std::mutex> lock(timer_mutex_); clock_t clock = static_cast<clock_t> (std::clock() * 1000 / CLOCKS_PER_SEC);
// list_timer_event ll; bool big_clock = false; for (int i = CountArrar(nxt_clock_) - 1; i >= 0; i--){ if (big_clock || clock >= nxt_clock_[i]){ big_clock = true; nxt_clock_[i] = clock + s_arr_timer[i]; for (auto it = timer_type_[i + 1].begin(); it != timer_type_[i + 1].end(); ){ if ((*it)->nxt_trigger_time_ - clock < s_arr_timer[i]){ // if (!add(*it)){ // ll.push_back(*it); // } timer_type_[i].push_back(*it); it = timer_type_[i + 1].erase(it); } else{ it++; } } } }
for (auto it = timer_type_[0].begin(); it != timer_type_[0].end();){ bool erase = false; if ((*it)->nxt_trigger_time_ <= clock){ (*it)->call_back_((*it)->data_);// need to post
if (--(*it)->repeat_ <= 0){ release_timer(*it); it = timer_type_[0].erase(it); erase = true; } else{ (*it)->nxt_trigger_time_ = clock + (*it)->interval_; if ((*it)->interval_ >= s_arr_timer[0]){ add(*it); it = timer_type_[0].erase(it); erase = true; } } } if (!erase){ it++; } }
// for (auto it : ll){ // if (--(it->repeat_) > 0){ // // post // it->nxt_trigger_time_ += it->interval_; // add(it); // } // it->call_back_(it->data_); // }
return true; }
void TimeWheel::add(TimerEvent* timer_event) { for (int i = CountArrar(nxt_clock_) - 1; i >= 0; i--){ if (timer_event->nxt_trigger_time_ >= nxt_clock_[i]){ timer_type_[i + 1].push_back(timer_event); return; } }
timer_type_[0].push_back(timer_event); return; }
uint32_t TimeWheel::add_timer(uint16_t server_id, int interval, void(*call_back)(void*), void* data, int repeat/* = 1*/){ if (interval <= 0){ return 0; } std::unique_lock<std::mutex> lock(timer_mutex_);
TimerEvent* timer_event = create_timer(); timer_event->timer_id_ = cur_time_id_++; timer_event->server_id_ = server_id; timer_event->interval_ = static_cast<clock_t>(interval); timer_event->call_back_ = call_back; timer_event->data_ = data; timer_event->nxt_trigger_time_ = timer_event->interval_ + static_cast<clock_t> (std::clock() * 1000 / CLOCKS_PER_SEC); timer_event->repeat_ = repeat;
add(timer_event); return timer_event->timer_id_; }
bool TimeWheel::delete_timer(uint32_t timer_id){ std::unique_lock<std::mutex> lock(timer_mutex_);
for (int i = 0; i < CountArrar(timer_type_); i++){ auto& ll = timer_type_[i]; for (auto it = ll.begin(); it != ll.end(); it++){ if ((*it)->timer_id_ == timer_id){ release_timer(*it); ll.erase(it); return true; } } }
return false; }
inline TimeWheel::TimerEvent* TimeWheel::create_timer(){ TimerEvent* timer_event = nullptr; if (timer_storage_.empty()){ try { timer_event = new TimerEvent; timer_all_.push_back(timer_event); } catch (...) { // log error exit(1); } } else{ timer_event = timer_storage_.front(); timer_storage_.pop_front(); } memset(timer_event, 0, sizeof(*timer_event)); return timer_event; }
inline void TimeWheel::release_timer(TimerEvent* timer_event){ timer_storage_.push_back(timer_event); }
// Time.cpp : 定义控制台应用程序的入口点。 // #include "TimeWheel.h" #include <thread> #include <iostream> using namespace std;
int _tmain(int argc, _TCHAR* argv[]) { TimeWheel* time_wheel = TimeWheel::get_instance(); std::thread t([&]{ time_wheel->init(); while (1){ if (!time_wheel->run_sink()){ break; } } }); t.detach();
time_wheel->add_timer(1, 100, [](void*){ cout << "100 is called" << endl; }, nullptr, 100);
int id = time_wheel->add_timer(1, 1000, [](void*){ cout << "1000 is called ***********" << endl; }, nullptr, 100);
time_wheel->add_timer(1, 10000, [](void*){ cout << "10000 is called" << endl; }, nullptr, 100);
time_wheel->add_timer(1, 300, [](void*){ cout << "300 is called" << endl; }, nullptr, 100);
int nloop = 0; while (1) { this_thread::sleep_for(chrono::milliseconds(1500)); time_wheel->add_timer(1, 1000, [](void*){ cout << "1000 2 is called" << endl; }, nullptr);
if (nloop++ == 2) time_wheel->delete_timer(id); }
return 0; }
