高性能服务器开发之C++定时器
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                高性能服务器开发之C++定时器
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.                        
                                高性能服務(wù)器開發(fā)之C++定時器
來源:?https://www.cnblogs.com/junye/p/5836552.html
寫這篇文章前搜了下網(wǎng)上類似的文章,有很多,所以筆者的這篇文章就不對定時器的常見實現(xiàn)方法加以說明,也不進行性能比較,直接上代碼。
基于multimap實現(xiàn)的比較簡單,這里略過。
?
前導
對于大多數(shù)的服務(wù)器程序,其定時器一般支持單線程就夠了,一般使用方法見下面代碼。如果需要多線程怎么辦,筆者一般用一個簡單的辦法:多線程的業(yè)務(wù)線程中不包含定時器管理器,單獨啟一個線程用來管理所有定時器,當時間觸發(fā)時,向業(yè)務(wù)線程投遞定時器消息即可。
#include <iostream> #include <thread> #include <chrono> #include "Timer.h"void TimerHandler() {std::cout << "TimerHandler" << std::endl; }int main() {TimerManager tm;Timer t(tm);t.Start(&TimerHandler, 1000);while (true){tm.DetectTimers();std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cin.get();return 0; }?
1 最小堆實現(xiàn)
#include <vector> #include <boost/function.hpp>class TimerManager;class Timer { public:enum TimerType { ONCE, CIRCLE };Timer(TimerManager& manager);~Timer();template<typename Fun>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_;boost::function<void(void)> timerFun_;unsigned interval_;unsigned long long expires_;size_t heapIndex_; };class TimerManager { public:static unsigned long long GetCurrentMillisecs();void DetectTimers(); private:friend class Timer;void AddTimer(Timer* timer);void RemoveTimer(Timer* timer);void UpHeap(size_t index);void DownHeap(size_t index);void SwapHeap(size_t, size_t index2);private:struct HeapEntry{unsigned long long time;Timer* timer;};std::vector<HeapEntry> heap_; };template<typename Fun> inline void Timer::Start(Fun fun, unsigned interval, TimerType timeType) {Stop();interval_ = interval;timerFun_ = fun;timerType_ = timeType;timer->expires_ = timer->interval_ + TimerManager::GetCurrentMillisecs();manager_.AddTimer(this); }// cpp file // #define _CRT_SECURE_NO_WARNINGS #include "config.h" #include "timer.h" #ifdef _MSC_VER # include <sys/timeb.h> #else # include <sys/time.h> #endif// // TimerTimer::Timer(TimerManager& manager): manager_(manager), heapIndex_(-1) { }Timer::~Timer() {Stop(); }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_(); }// // TimerManagervoid 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) {size_t 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();size_t parent = (index - 1) / 2;if (index > 0 && heap_[index].time < heap_[parent].time)UpHeap(index);elseDownHeap(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(size_t index) {size_t parent = (index - 1) / 2;while (index > 0 && heap_[index].time < heap_[parent].time){SwapHeap(index, parent);index = parent;parent = (index - 1) / 2;} }void TimerManager::DownHeap(size_t index) {size_t child = index * 2 + 1;while (child < heap_.size()){size_t 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 * 2 + 1;} }void TimerManager::SwapHeap(size_t index1, size_t 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() { #ifdef _MSC_VER_timeb timebuffer;_ftime(&timebuffer);unsigned long long ret = timebuffer.time;ret = ret * 1000 + timebuffer.millitm;return ret; #elsetimeval tv; ::gettimeofday(&tv, 0);unsigned long long ret = tv.tv_sec;return ret * 1000 + tv.tv_usec / 1000; #endif }?
2 時間輪實現(xiàn)
// header file // #pragma once #include <list> #include <vector> #include <boost/function.hpp>class TimerManager;class Timer { public:enum TimerType {ONCE, CIRCLE};Timer(TimerManager& manager);~Timer();template<typename Fun>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_;boost::function<void(void)> timerFun_;unsigned interval_;unsigned long long expires_;int vecIndex_;std::list<Timer*>::iterator itr_; };class TimerManager { public:TimerManager();static unsigned long long GetCurrentMillisecs();void DetectTimers();private:friend class Timer;void AddTimer(Timer* timer);void RemoveTimer(Timer* timer);int Cascade(int offset, int index);private:typedef std::list<Timer*> TimeList;std::vector<TimeList> tvec_;unsigned long long checkTime_; };template<typename Fun> inline void Timer::Start(Fun fun, unsigned interval, TimerType timeType) {Stop();interval_ = interval;timerFun_ = fun;timerType_ = timeType;expires_ = interval_ + TimerManager::GetCurrentMillisecs();manager_.AddTimer(this); }// cpp file //#define _CRT_SECURE_NO_WARNINGS #include "config.h" #include "timer2.h" #ifdef _MSC_VER # include <sys/timeb.h> #else # include <sys/time.h> #endif#define TVN_BITS 6 #define TVR_BITS 8 #define TVN_SIZE (1 << TVN_BITS) #define TVR_SIZE (1 << TVR_BITS) #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) #define OFFSET(N) (TVR_SIZE + (N) *TVN_SIZE) #define INDEX(V, N) ((V >> (TVR_BITS + (N) *TVN_BITS)) & TVN_MASK)// // TimerTimer::Timer(TimerManager& manager): manager_(manager), vecIndex_(-1) { }Timer::~Timer() {Stop(); }void Timer::Stop() {if (vecIndex_ != -1){manager_.RemoveTimer(this);vecIndex_ = -1;} }void Timer::OnTimer(unsigned long long now) {if (timerType_ == Timer::CIRCLE){expires_ = interval_ + now;manager_.AddTimer(this);}else{vecIndex_ = -1;}timerFun_(); }// // TimerManagerTimerManager::TimerManager() {tvec_.resize(TVR_SIZE + 4 * TVN_SIZE);checkTime_ = GetCurrentMillisecs(); }void TimerManager::AddTimer(Timer* timer) {unsigned long long expires = timer->expires_;unsigned long long idx = expires - checkTime_;if (idx < TVR_SIZE){timer->vecIndex_ = expires & TVR_MASK;}else if (idx < 1 << (TVR_BITS + TVN_BITS)){timer->vecIndex_ = OFFSET(0) + INDEX(expires, 0);}else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)){timer->vecIndex_ = OFFSET(1) + INDEX(expires, 1);}else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)){timer->vecIndex_ = OFFSET(2) + INDEX(expires, 2);}else if ((long long) idx < 0){timer->vecIndex_ = checkTime_ & TVR_MASK;}else{ if (idx > 0xffffffffUL){idx = 0xffffffffUL;expires = idx + checkTime_;}timer->vecIndex_ = OFFSET(3) + INDEX(expires, 3);}TimeList& tlist = tvec_[timer->vecIndex_];tlist.push_back(timer);timer->itr_ = tlist.end();--timer->itr_; }void TimerManager::RemoveTimer(Timer* timer) {TimeList& tlist = tvec_[timer->vecIndex_];tlist.erase(timer->itr_); }void TimerManager::DetectTimers() {unsigned long long now = GetCurrentMillisecs();while (checkTime_ <= now){int index = checkTime_ & TVR_MASK;if (!index &&!Cascade(OFFSET(0), INDEX(checkTime_, 0)) &&!Cascade(OFFSET(1), INDEX(checkTime_, 1)) &&!Cascade(OFFSET(2), INDEX(checkTime_, 2))){Cascade(OFFSET(3), INDEX(checkTime_, 3));}++checkTime_;TimeList& tlist = tvec_[index];TimeList temp;temp.splice(temp.end(), tlist);for (TimeList::iterator itr = temp.begin(); itr != temp.end(); ++itr){(*itr)->OnTimer(now);}} }int TimerManager::Cascade(int offset, int index) {TimeList& tlist = tvec_[offset + index];TimeList temp;temp.splice(temp.end(), tlist);for (TimeList::iterator itr = temp.begin(); itr != temp.end(); ++itr){AddTimer(*itr);}return index; }unsigned long long TimerManager::GetCurrentMillisecs() { #ifdef _MSC_VER_timeb timebuffer;_ftime(&timebuffer);unsigned long long ret = timebuffer.time;ret = ret * 1000 + timebuffer.millitm;return ret; #elsetimeval tv; ::gettimeofday(&tv, 0);unsigned long long ret = tv.tv_sec;return ret * 1000 + tv.tv_usec / 1000; #endif }?
結(jié)束語
在曾經(jīng)的很多項目中,定時器的實現(xiàn)都是使用map,也許效率不是太高,卻從來沒有成為性能的瓶頸。但是程序員通常是追求完美的,既然有更好解決方案,且其實現(xiàn)又不那么復雜,那就完全可以去嘗試。
?
轉(zhuǎn)載于:https://www.cnblogs.com/lsgxeva/p/8072468.html
總結(jié)
以上是生活随笔為你收集整理的高性能服务器开发之C++定时器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 《selenium2 python 自动
- 下一篇: 在html中用js代替${pagecon
