Skip to content

Instantly share code, notes, and snippets.

@baixiangcpp
Created January 22, 2019 08:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save baixiangcpp/63278c0087201a655f940ab8de543abd to your computer and use it in GitHub Desktop.
Save baixiangcpp/63278c0087201a655f940ab8de543abd to your computer and use it in GitHub Desktop.
A timer implemented with time wheel
#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