1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| ##include <sys/epoll.h> ##include <sys/timerfd.h> ##include <time.h> ##include <unistd.h>
##include <functional> ##include <chrono> ##include <set> ##include <memory> ##include <iostream>
using namespace std;
struct TimerNodeBase { time_t expire; uint64_t id; };
struct TimerNode : public TimerNodeBase { using Callback = std::function<void(const TimerNode &node)>; Callback func; TimerNode(int64_t id, time_t expire, Callback func) : func(func) { this->expire = expire; this->id = id; } };
bool operator < (const TimerNodeBase &lhd, const TimerNodeBase &rhd) { if (lhd.expire < rhd.expire) { return true; } else if (lhd.expire > rhd.expire) { return false; } else return lhd.id < rhd.id; }
class Timer { public: static inline time_t GetTick() { return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now().time_since_epoch()).count(); } TimerNodeBase AddTimer(int msec, TimerNode::Callback func) { time_t expire = GetTick() + msec; if (timeouts.empty() || expire <= timeouts.crbegin()->expire) { auto pairs = timeouts.emplace(GenID(), expire, std::move(func)); return static_cast<TimerNodeBase>(*pairs.first); } auto ele = timeouts.emplace_hint(timeouts.crbegin().base(), GenID(), expire, std::move(func)); return static_cast<TimerNodeBase>(*ele); } void DelTimer(TimerNodeBase &node) { auto iter = timeouts.find(node); if (iter != timeouts.end()) timeouts.erase(iter); }
void HandleTimer(time_t now) { auto iter = timeouts.begin(); while (iter != timeouts.end() && iter->expire <= now) { iter->func(*iter); iter = timeouts.erase(iter); } }
public: virtual void UpdateTimerfd(const int fd) { struct timespec abstime; auto iter = timeouts.begin(); if (iter != timeouts.end()) { abstime.tv_sec = iter->expire / 1000; abstime.tv_nsec = (iter->expire % 1000) * 1000000; } else { abstime.tv_sec = 0; abstime.tv_nsec = 0; } struct itimerspec its = { .it_interval = {}, .it_value = abstime }; timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, nullptr); }
private: static inline uint64_t GenID() { return gid++; } static uint64_t gid;
set<TimerNode, std::less<>> timeouts; }; uint64_t Timer::gid = 0;
int main() { int epfd = epoll_create(1); int timerfd = timerfd_create(CLOCK_MONOTONIC, 0); struct epoll_event ev = {.events=EPOLLIN | EPOLLET}; epoll_ctl(epfd, EPOLL_CTL_ADD, timerfd, &ev); unique_ptr<Timer> timer = make_unique<Timer>(); int i = 0; timer->AddTimer(1000, [&](const TimerNode &node) { cout << Timer::GetTick() << " node id:" << node.id << " revoked times:" << ++i << endl; });
timer->AddTimer(1000, [&](const TimerNode &node) { cout << Timer::GetTick() << " node id:" << node.id << " revoked times:" << ++i << endl; });
timer->AddTimer(3000, [&](const TimerNode &node) { cout << Timer::GetTick() << " node id:" << node.id << " revoked times:" << ++i << endl; });
auto node = timer->AddTimer(2100, [&](const TimerNode &node) { cout << Timer::GetTick() << " node id:" << node.id << " revoked times:" << ++i << endl; }); timer->DelTimer(node);
cout << "now time:" << Timer::GetTick() << endl;
struct epoll_event evs[64] = {0}; while (true) { timer->UpdateTimerfd(timerfd); int n = epoll_wait(epfd, evs, 64, -1); time_t now = Timer::GetTick(); for (int i = 0; i < n; i++) { } timer->HandleTimer(now); } epoll_ctl(epfd, EPOLL_CTL_DEL, timerfd, &ev); close(timerfd); close(epfd); return 0; }
|