c++定时器
定时器作为常用的组件,通常的实现方式有几种:链表,最小堆,时间轮,等等。
1 链表
性能比较弱,适用于简单的场景,查询、插入、删除效率都不高
2 最小堆
性能比较高,适用于定时器需求较多的场景
3 时间轮
性能比较高,适用于定时器需求很大的场景
在网上查了一些资料,真正可以直接用的代码并不多,不可以直接运行,就不能给读者以更加感性的认识,也就不愿意更多的去分析代码和学习。所以,以 https://www.cnblogs.com/junye/p/5836552.html 为例,将它的最小堆实现,做了一些修改,可以接在gcc 4.8.2以上的环境编译通过并运行。将代码保存为 a.cc,编译命令为
g++ -g -o a a.cc -std=c++11
具体的代码如下:
#include <iostream> #include <chrono> #include <thread> #include <vector> #include <sys/time.h> // global declaration typedef void (*Fun)(void); class Timer; class TimerManager; // header file for Timer class Timer { public: enum TimerType { ONCE, CIRCLE }; Timer(TimerManager& manager); ~Timer(); void Start(Fun fun, unsigned interval, TimerType timeType = CIRCLE); void Stop(); private: void OnTimer(unsigned long long now); private: friend class TimerManager; TimerManager& manager_; TimerType timerType_; Fun timerFun_; unsigned interval_; unsigned long long expires_; int heapIndex_; }; // header file for TimerManager class TimerManager { public: static unsigned long long GetCurrentMillisecs(); void DetectTimers(); private: friend class Timer; void AddTimer(Timer* timer); void RemoveTimer(Timer* timer); void UpHeap(int index); void DownHeap(int index); void SwapHeap(int, int index2); private: struct HeapEntry { unsigned long long time; Timer* timer; }; std::vector<HeapEntry> heap_; }; // implemetation of Timer Timer::Timer(TimerManager& manager) : manager_(manager) , heapIndex_(-1) { // to-do } Timer::~Timer() { Stop(); } inline void Timer::Start(Fun fun, unsigned interval, TimerType timeType) { Stop(); interval_ = interval; timerFun_ = fun; timerType_ = timeType; this->expires_ = this->interval_ + TimerManager::GetCurrentMillisecs(); manager_.AddTimer(this); } void Timer::Stop() { if (heapIndex_ != -1) { manager_.RemoveTimer(this); heapIndex_ = -1; } } void Timer::OnTimer(unsigned long long now) { if (timerType_ == Timer::CIRCLE) { expires_ = interval_ + now; manager_.AddTimer(this); } else { heapIndex_ = -1; } timerFun_(); } // implemetation of TimerManager void TimerManager::AddTimer(Timer* timer) { timer->heapIndex_ = heap_.size(); HeapEntry entry = { timer->expires_, timer }; heap_.push_back(entry); UpHeap(heap_.size() - 1); } void TimerManager::RemoveTimer(Timer* timer) { int index = timer->heapIndex_; if (!heap_.empty() && index < heap_.size()) { if (index == heap_.size() - 1) { heap_.pop_back(); } else { SwapHeap(index, heap_.size() - 1); heap_.pop_back(); int parent = (index - 1) / 2; if (index > 0 && heap_[index].time < heap_[parent].time) { UpHeap(index); } else { DownHeap(index); } } } } void TimerManager::DetectTimers() { unsigned long long now = GetCurrentMillisecs(); while (!heap_.empty() && heap_[0].time <= now) { Timer* timer = heap_[0].timer; RemoveTimer(timer); timer->OnTimer(now); } } void TimerManager::UpHeap(int index) { int parent = index >> 1; while (index > 0 && heap_[index].time < heap_[parent].time) { SwapHeap(index, parent); index = parent; parent = index >> 1; } } void TimerManager::DownHeap(int index) { int child = (index << 1) + 1; while (child < heap_.size()) { int minChild = (child + 1 == heap_.size() || heap_[child].time < heap_[child + 1].time)? child : child + 1; if (heap_[index].time < heap_[minChild].time) break; SwapHeap(index, minChild); index = minChild; child = (index << 1) + 1; } } void TimerManager::SwapHeap(int index1, int index2) { HeapEntry tmp = heap_[index1]; heap_[index1] = heap_[index2]; heap_[index2] = tmp; heap_[index1].timer->heapIndex_ = index1; heap_[index2].timer->heapIndex_ = index2; } unsigned long long TimerManager::GetCurrentMillisecs() { timeval tv; ::gettimeofday(&tv, 0); unsigned long long ret = tv.tv_sec; return ret * 1000 + tv.tv_usec / 1000; } // test code void TimerHandler_1() { std::cout << "TimerHandler_1" << std::endl; } void TimerHandler_2() { std::cout << "TimerHandler_2" << std::endl; } void TimerHandler_3() { std::cout << "TimerHandler_3" << std::endl; } void TimerHandler_4() { std::cout << "TimerHandler_4" << std::endl; } int main() { TimerManager tm; Timer t1(tm); t1.Start(&TimerHandler_1, 1000); Timer t2(tm); t2.Start(&TimerHandler_2, 500); Timer t3(tm); t3.Start(&TimerHandler_3, 1500); Timer t4(tm); t4.Start(&TimerHandler_4, 100); while (true) { tm.DetectTimers(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } return 0; }