//
// Created by DELL on 2022/4/27.
//
#ifndef TIMINGWHEEL_TIMING_WHEEL_H
#define TIMINGWHEEL_TIMING_WHEEL_H
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <list>
#include <thread>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <functional>
#include <cassert>
#include <cstring>
#define TIME_WHEEL_SIZE_ 6
typedef std::function<void(void)> timeout_cb;
struct timer_node {
// struct timer_node *next;
int rotation;
timeout_cb proc; //timeout callback
timer_node(int after, timeout_cb f = nullptr, int tloop = 1) : rotation(tloop), proc(f) {
}
bool
operator==(timer_node timer) {
return rotation == timer.rotation;
}
};
typedef std::list<timer_node> clock_list_t;
template<class U=std::chrono::seconds>
class timer_wheel {
typedef U timeUnit;
int TIME_WHEEL_SIZE;
clock_list_t **slots;
int current_ = 0;
int min_interval_ = 1;
std::thread *worker;
std::thread *execWorker;
std::condition_variable timeout;
std::mutex lock_;
std::mutex queue_lock_;
std::queue<std::function<void(void)>> timeoutQueue;
bool exec_in_timerThread;
template<class T>
friend void sleep_for_a_while(timer_wheel<T> *timerWheel);
protected:
void
timerThread() {
while (1) {
std::lock_guard<std::mutex> lockGuard(lock_);
tick();
sleep_for_a_while(this);
}
}
void
execThread() {
while (1) {
std::unique_lock<std::mutex> lock(queue_lock_);
while (timeoutQueue.empty()) {
timeout.wait(lock);
}
while (!timeoutQueue.empty()) {
auto &&f = timeoutQueue.front();
timeoutQueue.pop();
f();
}
lock.unlock();
}
}
public:
timer_wheel(int TimeWheelLoopSize = 6,
int min_interval_unit = 1) : TIME_WHEEL_SIZE(TimeWheelLoopSize),
exec_in_timerThread(false),
min_interval_(min_interval_unit),
worker(nullptr),
slots(nullptr),
execWorker(nullptr) {
worker = new std::thread(&timer_wheel::timerThread, this);
slots = new clock_list_t *[TimeWheelLoopSize]();
if (!exec_in_timerThread)
execWorker = new std::thread(&timer_wheel::execThread, this);
}
template<class dura_t= std::chrono::seconds>
bool addEvent(int unit, timeout_cb action = [](){}) {
std::lock_guard<std::mutex> lockGuard(lock_);
dura_t ds(unit);
int second = std::chrono::duration_cast<U>(ds).count();
if (second >= min_interval_) {
int slot_pos = (second / min_interval_ + current_) % TIME_WHEEL_SIZE;
auto n_pass = second / (min_interval_ * TIME_WHEEL_SIZE);
if (!slots[slot_pos]) {
slots[slot_pos] = new clock_list_t();
}
slots[slot_pos]->push_back(timer_node(second, action, n_pass));
return true;
} else {
std::cerr << "time unit not qualified, addEvent failed at" << __FILE__;
// failed, already timeout
return false;
}
}
public:
~timer_wheel() {
delete[] slots;
delete worker;
delete execWorker;
}
protected:
void tick() {
clock_list_t *curList = slots[current_];
if (curList) {
for (auto &&iter = curList->begin(); iter != curList->end();) {
//time do not out, wait until the next round
if ((*iter).rotation > 0) {
(*iter).rotation--;
++iter;
} else {
// timeout, execute callback, and delete timer node
// exec in another thread
std::lock_guard<std::mutex> qLockGuard(queue_lock_);
auto f = std::bind([](timer_node &timer) {
if (timer.proc) {
timer.proc();
}
}, std::move(*iter));
if (exec_in_timerThread) {
f();
} else {
timeoutQueue.push(f);
}
curList->erase(iter++);
}
}
CleanTimeout:
timeout.notify_all();
}
// printf("exit tick\n");
stepOut:
current_ = (current_ + 1) % TIME_WHEEL_SIZE;
}
};
template<class U>
void
sleep_for_a_while(timer_wheel<U> *timerWheel) {
std::this_thread::sleep_for(U(timerWheel->min_interval_));
}
#endif //TIMINGWHEEL_TIMING_WHEEL_H```
C++时间轮,TimeWheel
最新推荐文章于 2022-09-06 22:58:17 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)