Created
January 22, 2019 08:45
-
-
Save baixiangcpp/63278c0087201a655f940ab8de543abd to your computer and use it in GitHub Desktop.
A timer implemented with time wheel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <functional> | |
#include <vector> | |
#include <iostream> | |
#include <algorithm> | |
#include <sys/epoll.h> | |
#include <sys/time.h> | |
#include <unistd.h> | |
class Timer | |
{ | |
public: | |
Timer(int rotations, int slot, std::function<void(void)> fun, void *args) | |
: rotations_(rotations), slot_(slot), fun(fun) | |
{ | |
} | |
inline int getRotations() { return rotations_; } | |
inline void decreaseRotations() { --rotations_; } | |
inline void active() { fun(); } | |
inline int getSlot() { return slot_; } | |
private: | |
int rotations_; | |
int slot_; | |
std::function<void(void)> fun; | |
void *args; | |
}; | |
class TimeWheel | |
{ | |
public: | |
TimeWheel(int nslots) | |
: nslosts_(nslots), curslot_(0), | |
slots_(nslosts_, std::vector<Timer *>()), starttime_(getCurrentMillisecs()) | |
{ | |
} | |
~TimeWheel() | |
{ | |
for (std::vector<Timer *> vect : slots_) | |
for (Timer *timer : vect) | |
delete timer; | |
} | |
unsigned long long getCurrentMillisecs() | |
{ | |
struct timespec ts; | |
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); | |
return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000); | |
} | |
Timer *addTimer(unsigned long long timeout, std::function<void(void)> fun, void *args) | |
{ | |
int slot = 0; | |
Timer *timer = NULL; | |
if (timeout < 0) | |
return NULL; | |
slot = (curslot_ + (timeout % nslosts_)) % nslosts_; | |
timer = new Timer(timeout / nslosts_, slot, fun, args); | |
slots_[slot].push_back(timer); | |
return timer; | |
} | |
void delTimer(Timer *timer) | |
{ | |
if (!timer) | |
return; | |
std::vector<Timer *>::iterator it = std::find(slots_[timer->getSlot()].begin(), slots_[timer->getSlot()].end(), timer); | |
if (it != slots_[timer->getSlot()].end()) | |
{ | |
slots_[timer->getSlot()].erase(it); | |
//delete timer; | |
} | |
} | |
void tick() | |
{ | |
for (auto it = slots_[curslot_].begin(); it != slots_[curslot_].end();) | |
{ | |
if ((*it)->getRotations() > 0) | |
{ | |
(*it)->decreaseRotations(); | |
++it; | |
continue; | |
} | |
else | |
{ | |
Timer *timer = *it; | |
timer->active(); | |
it = slots_[curslot_].erase(it); | |
delete timer; | |
} | |
} | |
curslot_ = ++curslot_ % nslosts_; | |
} | |
void takeAllTimeout() | |
{ | |
int now = getCurrentMillisecs(); | |
int cnt = now - starttime_; | |
for (int i = 0; i < cnt; ++i) | |
tick(); | |
starttime_ = now; | |
} | |
private: | |
int nslosts_; | |
int curslot_; | |
unsigned long long starttime_; | |
std::vector<std::vector<Timer *>> slots_; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment