// Copyright 2019, Chen Shuaihao.
//
//Author: Chen Shuaihao
//
//
#include "TimerManager.h"
#include
#include
#include
#include
#include
#include
#include
//åå§å
TimerManager* TimerManager::ptimermanager_ = nullptr;
std::mutex TimerManager::mutex_;
TimerManager::GC TimerManager::gc;
const int TimerManager::slotinterval = 1;
const int TimerManager::slotnum = 1024;
TimerManager::TimerManager(/* args */)
: currentslot(0),
timewheel(slotnum, nullptr),
running_(false),
th_()
{
}
TimerManager::~TimerManager()
{
Stop();
}
TimerManager* TimerManager::GetTimerManagerInstance()
{
if(ptimermanager_ == nullptr) //æé为空ï¼åå建管çå¨
{
std::lock_guard<:mutex> lock(mutex_);
if(ptimermanager_ == nullptr) //å鿣æµ
{
ptimermanager_ = new TimerManager();
}
}
return ptimermanager_;
}
void TimerManager::AddTimer(Timer* ptimer)
{
if(ptimer == nullptr)
return;
std::lock_guard<:mutex> lock(timewheelmutex_);
CalculateTimer(ptimer);
AddTimerToTimeWheel(ptimer);
}
void TimerManager::RemoveTimer(Timer* ptimer)
{
if(ptimer == nullptr)
return;
std::lock_guard<:mutex> lock(timewheelmutex_);
RemoveTimerFromTimeWheel(ptimer);
}
void TimerManager::AdjustTimer(Timer* ptimer)
{
if(ptimer == nullptr)
return;
std::lock_guard<:mutex> lock(timewheelmutex_);
AdjustTimerToWheel(ptimer);
}
void TimerManager::CalculateTimer(Timer* ptimer)
{
if(ptimer == nullptr)
return;
int tick = 0;
int timeout = ptimer->timeout_;
if(timeout < slotinterval)
{
tick = 1; //ä¸è¶³ä¸ä¸ªsloté´éï¼æå»¶è¿1slot计ç®
}
else
{
tick = timeout / slotinterval;
}
ptimer->rotation = tick / slotnum;
int timeslot = (currentslot + tick) % slotnum;
ptimer->timeslot = timeslot;
}
void TimerManager::AddTimerToTimeWheel(Timer* ptimer)
{
if(ptimer == nullptr)
return;
int timeslot = ptimer->timeslot;
if(timewheel[timeslot])
{
ptimer->next = timewheel[timeslot];
timewheel[timeslot]->prev = ptimer;
timewheel[timeslot] = ptimer;
}
else
{
timewheel[timeslot] = ptimer;
}
}
void TimerManager::RemoveTimerFromTimeWheel(Timer* ptimer)
{
if(ptimer == nullptr)
return;
int timeslot = ptimer->timeslot;
if(ptimer == timewheel[timeslot])
{
//头ç»ç¹
timewheel[timeslot] = ptimer->next;
if(ptimer->next != nullptr)
{
ptimer->next->prev = nullptr;
}
ptimer->prev = ptimer->next = nullptr;
}
else
{
if(ptimer->prev == nullptr) //ä¸å¨æ¶é´è½®çé¾è¡¨ä¸ï¼å³å·²ç»è¢«å é¤äº
return;
ptimer->prev->next = ptimer->next;
if(ptimer->next != nullptr)
ptimer->next->prev = ptimer->prev;
ptimer->prev = ptimer->next = nullptr;
}
}
void TimerManager::AdjustTimerToWheel(Timer* ptimer)
{
if(ptimer == nullptr)
return;
RemoveTimerFromTimeWheel(ptimer);
CalculateTimer(ptimer);
AddTimerToTimeWheel(ptimer);
}
void TimerManager::CheckTimer()//æ§è¡å½åslotçä»»å¡
{
std::lock_guard<:mutex> lock(timewheelmutex_);
Timer *ptimer = timewheel[currentslot];
while(ptimer != nullptr)
{
if(ptimer->rotation > 0)
{
--ptimer->rotation;
ptimer = ptimer->next;
}
else
{
//坿§è¡å®æ¶å¨ä»»å¡
ptimer->timercallback_(); //注æï¼ä»»å¡éä¸è½æå®æ¶å¨èªèº«ç»æ¸
çæï¼ï¼ï¼æè®¤ä¸ºåºè¯¥å
ç§»é¤åæ§è¡ä»»å¡
if(ptimer->timertype_ == Timer::TimerType::TIMER_ONCE)
{
Timer *ptemptimer = ptimer;
ptimer = ptimer->next;
RemoveTimerFromTimeWheel(ptemptimer);
}
else
{
Timer *ptemptimer = ptimer;
ptimer = ptimer->next;
AdjustTimerToWheel(ptemptimer);
if(currentslot == ptemptimer->timeslot && ptemptimer->rotation > 0)
{
//妿宿¶å¨å¤äºä¸è½¬çè¯ï¼éè¦å
对rotationå1ï¼å¦åä¼çå¾
ä¸¤ä¸ªå¨æ
--ptemptimer->rotation;
}
}
}
}
currentslot = (++currentslot) % TimerManager::slotnum; //ç§»å¨è³ä¸ä¸ä¸ªæ¶é´æ§½
}
void TimerManager::CheckTick()
{
// steady_clock::time_point t1 = steady_clock::now();
// steady_clock::time_point t2 = steady_clock::now();
// duration time_span;
int si = TimerManager::slotinterval;
struct timeval tv;
gettimeofday(&tv, NULL);
int oldtime = (tv.tv_sec % 10000) * 1000 + tv.tv_usec / 1000;
int time;
int tickcount;
while(running_)
{
gettimeofday(&tv, NULL);
time = (tv.tv_sec % 10000) * 1000 + tv.tv_usec / 1000;
tickcount = (time - oldtime)/slotinterval; //计ç®ä¸¤æ¬¡checkçæ¶é´é´éå å¤å°ä¸ªslot
//oldtime = time;
oldtime = oldtime + tickcount*slotinterval;
for(int i = 0; i < tickcount; ++i)
{
TimerManager::GetTimerManagerInstance()->CheckTimer();
}
std::this_thread::sleep_for(std::chrono::microseconds(500)); //milliseconds(si)æ¶é´ç²åº¦è¶å°ï¼å»¶æ¶è¶ä¸ç²¾ç¡®ï¼å 为ä¸ä¸æåæ¢èæ¶
// t2 = steady_clock::now();
// time_span = duration_cast>(t2 - t1);
// t1 = t2;
// std::cout << "thread " << time_span.count() << " seconds." << std::endl;
}
}
void TimerManager::Start()
{
running_ = true;
th_ = std::thread(&TimerManager::CheckTick, this);
}
void TimerManager::Stop()
{
running_ = false;
if(th_.joinable())
th_.join();
}
// using namespace std::chrono;
// // æµè¯
// class Test
// {
// public:
// steady_clock::time_point t1;
// Test(/* args */) : t1(steady_clock::now())
// {
// }
// ~Test()
// {
// }
// void func()
// {
// //std::cout << "timer test..."<< std::endl;
// steady_clock::time_point t2 = steady_clock::now();
// duration time_span = duration_cast>(t2 - t1);
// t1 = t2;
// std::cout << "It took me " << time_span.count() << " seconds." << std::endl;
// }
// };
// //timer unit test
// int main()
// {
// Test test1;
// Test test2;
// TimerManager *ptimermanager = TimerManager::GetTimerManagerInstance();
// //ptimermanager->AddTimer(1000, Timer::TimerType::TIMER_ONCE, std::bind(&Test::func, &test));
// //ptimermanager->AddTimer(2000, Timer::TimerType::TIMER_PERIOD, std::bind(&Test::func, &test0));
// //ptimermanager->AddTimer(1000, Timer::TimerType::TIMER_PERIOD, std::bind(&Test::func, &test2));
// ptimermanager->Start();
// std::this_thread::sleep_for(std::chrono::seconds(2));
// std::cout << "set timer "<< std::endl;
// Timer *timer1 = new Timer(100, Timer::TimerType::TIMER_PERIOD, std::bind(&Test::func, &test1));
// timer1->Start();
// Timer *timer2 = new Timer(200, Timer::TimerType::TIMER_PERIOD, std::bind(&Test::func, &test2));
// timer2->Start();
// std::this_thread::sleep_for(std::chrono::seconds(2));
// //timer1->Stop();
// //timer2->Stop();
// std::cout << "stop timer "<< std::endl;
// Test test3;
// Timer *timer3 = new Timer(300, Timer::TimerType::TIMER_PERIOD, std::bind(&Test::func, &test3));
// timer3->Start();
// //std::this_thread::sleep_for(std::chrono::seconds(3));
// timer3->Adjust(500, Timer::TimerType::TIMER_ONCE, std::bind(&Test::func, &test3));
// std::this_thread::sleep_for(std::chrono::seconds(2));
// delete timer1;
// delete timer2;
// ptimermanager->Stop();
// return 0;
// }