Skip to content

Instantly share code, notes, and snippets.

@baixiangcpp
Created January 22, 2019 06:35
Show Gist options
  • Select an option

  • Save baixiangcpp/b2199f1f1c7108f22f47d2ca617f6960 to your computer and use it in GitHub Desktop.

Select an option

Save baixiangcpp/b2199f1f1c7108f22f47d2ca617f6960 to your computer and use it in GitHub Desktop.
A timer implemented with priority queue
#include <functional>
#include <iostream>
#include <algorithm>
#include <sys/epoll.h>
#include <sys/time.h>
#include <unistd.h>
#include <queue>
#include <vector>
class Timer
{
public:
Timer(unsigned long long expire, std::function<void(void)> fun, void *args)
: expire_(expire), fun(fun)
{
}
inline void active() { fun(); }
inline unsigned long long getExpire() const{ return expire_; }
private:
std::function<void(void)> fun;
void *args;
unsigned long long expire_;
};
class TimerManager
{
public:
TimerManager() {}
Timer *addTimer(int timeout, std::function<void(void)> fun, void *args = NULL)
{
if(timeout <= 0)
return NULL;
unsigned long long now = getCurrentMillisecs();
Timer* timer = new Timer( now+timeout, fun, args);
queue_.push(timer);
return timer;
}
void delTimer(Timer* timer)
{
std::priority_queue<Timer*,std::vector<Timer*>,cmp> newqueue;
while( !queue_.empty() )
{
Timer* top = queue_.top();
queue_.pop();
if( top != timer )
newqueue.push(top);
}
queue_ = newqueue;
}
unsigned long long getRecentTimeout()
{
unsigned long long timeout = -1;
if( queue_.empty() )
return timeout;
unsigned long long now = getCurrentMillisecs();
timeout = queue_.top()->getExpire() - now;
if(timeout < 0)
timeout = 0;
return timeout;
}
void takeAllTimeout()
{
unsigned long long now = getCurrentMillisecs();
while ( !queue_.empty() )
{
Timer* timer = queue_.top();
if( timer->getExpire() <= now )
{
queue_.pop();
timer->active();
delete timer;
continue;
}
return;
}
}
unsigned long long getCurrentMillisecs()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);
}
private:
struct cmp
{
bool operator()(Timer*& lhs, Timer*& rhs) const { return lhs->getExpire() > rhs->getExpire(); }
};
std::priority_queue<Timer*,std::vector<Timer*>,cmp> queue_;
};
@dongziqi
Copy link
Copy Markdown

真牛逼,感觉自己啥也不会,哈哈

@kohakus
Copy link
Copy Markdown

kohakus commented Jul 19, 2020

Nice implementation.
One more question. I'm curious about the delete operation of timer, it seems that STL heap function series cannot provide a efficient way here.

@evenstars
Copy link
Copy Markdown

Nice implementation.
One more question. I'm curious about the delete operation of timer, it seems that STL heap function series cannot provide a efficient way here.

In my opinion, we can use red-black tree to replace the priority-queue here

@etorth
Copy link
Copy Markdown

etorth commented Jan 1, 2022

  1. std::function is a closure, if you already using it as callback , there is no point to take the args.
  2. You can just put the Timer class into pirority_queue, no need to make a pointer of it, don't worry of copy, stl uses move.

everything other looks good.
Reading this to prepare for a embeded field interview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment