hikyuu2/hikyuu_cpp/hikyuu/utilities/TimerManager.h

471 lines
18 KiB
C++
Raw Normal View History

2021-01-09 00:11:16 +08:00
/*
* Copyright(C) 2021 hikyuu.org
*
* Create on: 2021-01-08
* Author: fasiondog
*/
#pragma once
2021-01-10 00:19:12 +08:00
#include <forward_list>
2021-01-10 17:41:06 +08:00
#include "../datetime/Datetime.h"
#include "../Log.h"
#include "thread/ThreadPool.h"
2021-01-09 00:11:16 +08:00
namespace hku {
2021-01-10 17:41:06 +08:00
/**
*
* @ingroup Utilities
*/
2021-01-09 00:11:16 +08:00
class TimerManager {
public:
2021-01-10 17:41:06 +08:00
TimerManager(const TimerManager&) = delete;
TimerManager(TimerManager&) = delete;
TimerManager(TimerManager&&) = delete;
TimerManager& operator=(const TimerManager&) = delete;
TimerManager& operator=(TimerManager&) = delete;
TimerManager& operator=(TimerManager&&) = delete;
/**
* start
2021-01-14 22:44:34 +08:00
* @param work_num 线线
2021-01-10 17:41:06 +08:00
*/
2021-01-14 22:44:34 +08:00
TimerManager(size_t work_num = std::thread::hardware_concurrency())
: m_current_timer_id(-1), m_stop(true), m_work_num(work_num) {}
2021-01-09 00:11:16 +08:00
2021-01-10 17:41:06 +08:00
/** 析构函数 */
2021-01-10 00:19:12 +08:00
~TimerManager() {
2021-01-17 21:28:16 +08:00
if (!m_stop) {
IntervalS s;
s.m_time_point = Datetime::min();
std::unique_lock<std::mutex> lock(m_mutex);
m_queue.push(s);
lock.unlock();
m_cond.notify_all();
if (m_detect_thread.joinable()) {
m_detect_thread.join();
}
}
2021-01-23 23:03:28 +08:00
for (auto iter = m_timers.begin(); iter != m_timers.end(); ++iter) {
delete iter->second;
}
2021-01-10 00:19:12 +08:00
}
2021-01-09 00:11:16 +08:00
2021-01-10 17:41:06 +08:00
/** 启动调度, 可在停止后重新启动 */
2021-01-09 00:11:16 +08:00
void start() {
2021-01-10 00:19:12 +08:00
if (m_stop) {
m_stop = false;
if (!m_tg) {
2021-01-14 22:44:34 +08:00
m_tg = std::make_unique<ThreadPool>(m_work_num);
2021-01-10 00:19:12 +08:00
}
/*
* timer timer
*/
std::forward_list<int> invalid_timers; // 记录已无效的 timer
std::unique_lock<std::mutex> lock(m_mutex);
for (auto iter = m_timers.begin(); iter != m_timers.end(); ++iter) {
int time_id = iter->first;
Timer* timer = iter->second;
Datetime now = Datetime::now();
2021-01-10 17:41:06 +08:00
// 记录已失效的 timer id
if (timer->m_repeat_num <= 0 || (timer->m_end_date != Datetime::max() &&
2021-01-12 00:37:00 +08:00
timer->m_end_date + timer->m_end_time < now)) {
2021-01-10 00:19:12 +08:00
invalid_timers.push_front(time_id);
2021-01-10 17:41:06 +08:00
continue;
}
IntervalS s;
s.m_timer_id = time_id;
2021-01-12 00:37:00 +08:00
if (timer->m_start_time < TimeDelta()) {
Datetime first_start_time = timer->m_start_date + timer->m_end_time;
if (first_start_time >= now) {
s.m_time_point = first_start_time;
2021-01-10 17:41:06 +08:00
} else {
2021-01-12 00:37:00 +08:00
if (timer->m_repeat_num <= 1) {
invalid_timers.push_front(time_id);
continue;
}
s.m_time_point = now.startOfDay() + timer->m_end_time;
if (s.m_time_point < now) {
s.m_time_point = s.m_time_point + TimeDelta(1);
}
}
} else {
s.m_time_point =
timer->m_start_date >= now.startOfDay()
? timer->m_start_date + timer->m_start_time + timer->m_duration
: now + timer->m_duration;
if (timer->m_start_time != timer->m_end_time) {
Datetime point_date = s.m_time_point.startOfDay();
TimeDelta point = s.m_time_point - point_date;
if (point < timer->m_start_time) {
s.m_time_point = point_date + timer->m_start_time;
} else if (point > timer->m_end_time) {
s.m_time_point = point_date + timer->m_start_time + TimeDelta(1);
} else {
TimeDelta gap = point - timer->m_start_time;
if (gap % timer->m_duration != TimeDelta()) {
int x = int(gap / timer->m_duration) + 1;
s.m_time_point =
point_date + timer->m_start_time + timer->m_duration * double(x);
}
2021-01-10 00:19:12 +08:00
}
}
}
2021-01-10 17:41:06 +08:00
m_queue.push(s);
2021-01-10 00:19:12 +08:00
}
// 清除已无效的 timer
for (auto id : invalid_timers) {
removeTimer(id);
}
lock.unlock();
m_cond.notify_all();
2021-01-16 00:15:28 +08:00
m_detect_thread = std::move(std::thread([this]() { detectThread(); }));
2021-01-10 00:19:12 +08:00
}
2021-01-09 00:11:16 +08:00
}
2021-01-10 17:41:06 +08:00
/** 终止调度 */
2021-01-09 00:11:16 +08:00
void stop() {
2021-01-10 00:19:12 +08:00
if (!m_stop) {
std::unique_lock<std::mutex> lock(m_mutex);
std::priority_queue<IntervalS> queue;
m_queue.swap(queue);
2021-01-15 00:19:38 +08:00
m_stop = true;
2021-01-10 00:19:12 +08:00
lock.unlock();
m_cond.notify_all();
}
2021-01-16 00:15:28 +08:00
if (m_detect_thread.joinable()) {
m_detect_thread.join();
}
2021-01-09 00:11:16 +08:00
}
2021-01-10 17:41:06 +08:00
/**
2021-01-11 00:22:08 +08:00
* ,
2021-01-10 17:41:06 +08:00
* @tparam F
* @tparam Args
2021-01-11 00:22:08 +08:00
* @param start_date
* @param end_date
* @param start_time
* @param end_time
* @param repeat_num 0std::numeric_limits<int>::max()
* @param delay TimeDelta(0)
2021-01-10 17:41:06 +08:00
* @param f
* @param args
*/
template <typename F, typename... Args>
2021-01-11 00:22:08 +08:00
void addFunc(Datetime start_date, Datetime end_date, TimeDelta start_time, TimeDelta end_time,
int repeat_num, TimeDelta duration, F&& f, Args&&... args) {
HKU_CHECK(!start_date.isNull(), "Invalid start_date!");
HKU_CHECK(!end_date.isNull(), "Invalid end_date!");
2021-01-12 23:48:43 +08:00
Datetime start = start_date.startOfDay();
Datetime end = end_date.startOfDay();
HKU_CHECK(end >= start, "end_date({}) need > start_date({})!", end, start);
HKU_CHECK(start_time >= TimeDelta(0) && start_time <= TimeDelta(0, 23, 59, 59, 999, 999),
2021-01-11 00:22:08 +08:00
"Invalid start_time: {}", start_time.repr());
2021-01-12 23:48:43 +08:00
HKU_CHECK(end_time >= TimeDelta(0) && end_time <= TimeDelta(0, 23, 59, 59, 999, 999),
2021-01-11 00:22:08 +08:00
"Invalid end_time: {}", end_time.repr());
HKU_CHECK(end_time >= start_time, "end_time({}) need >= start_time({})!", end_time,
start_time);
HKU_CHECK(repeat_num > 0, "Invalid repeat_num: {}", repeat_num);
HKU_CHECK(duration > TimeDelta(0), "Invalid duration: {}", duration.repr());
2021-01-12 23:48:43 +08:00
_addFunc(start, end, start_time, end_time, repeat_num, duration, std::forward<F>(f),
std::forward<Args>(args)...);
2021-01-11 00:22:08 +08:00
}
2021-01-09 00:11:16 +08:00
2021-01-11 00:22:08 +08:00
/**
*
* @tparam F
* @tparam Args
* @param repeat_num 0std::numeric_limits<int>::max()
* @param delay TimeDelta(0)
* @param f
* @param args
* @return true | false
*/
template <typename F, typename... Args>
void addDurationFunc(int repeat_num, TimeDelta duration, F&& f, Args&&... args) {
HKU_CHECK(repeat_num > 0, "Invalid repeat_num: {}, must > 0", repeat_num);
HKU_CHECK(duration > TimeDelta(), "Invalid duration: {}, must > TimeDelta(0)!",
duration.repr());
_addFunc(Datetime::min(), Datetime::max(), TimeDelta(), TimeDelta(), repeat_num, duration,
std::forward<F>(f), std::forward<Args>(args)...);
}
2021-01-10 17:41:06 +08:00
2021-01-11 00:22:08 +08:00
/**
* ,
* @tparam F
* @tparam Args
* @param delay TimeDelta(0)
* @param f
* @param args
*/
template <typename F, typename... Args>
void addDelayFunc(TimeDelta delay, F&& f, Args&&... args) {
2021-01-12 23:48:43 +08:00
HKU_CHECK(delay > TimeDelta(), "Invalid delay: {}, must > TimeDelta(0)!", delay);
2021-01-11 00:22:08 +08:00
_addFunc(Datetime::min(), Datetime::max(), TimeDelta(), TimeDelta(), 1, delay,
std::forward<F>(f), std::forward<Args>(args)...);
2021-01-09 00:11:16 +08:00
}
2021-01-11 00:22:08 +08:00
/**
* ,
* @tparam F
* @tparam Args
2021-01-12 23:48:43 +08:00
* @param time_point ...
2021-01-11 00:22:08 +08:00
*/
template <typename F, typename... Args>
2021-01-12 00:37:00 +08:00
void addFuncAtTime(Datetime time_point, F&& f, Args&&... args) {
Datetime now = Datetime::now();
HKU_CHECK(time_point > now, "You want run at {}, but now is {}", time_point, now);
2021-01-12 23:48:43 +08:00
Datetime point_date = time_point.startOfDay();
TimeDelta point = time_point - point_date;
_addFunc(time_point.startOfDay(), Datetime::max(), TimeDelta(-1), point, 1, TimeDelta(),
2021-01-11 00:22:08 +08:00
std::forward<F>(f), std::forward<Args>(args)...);
}
2021-01-10 00:19:12 +08:00
2021-01-12 00:37:00 +08:00
/**
2021-01-12 23:48:43 +08:00
* ,
2021-01-12 00:37:00 +08:00
* @tparam F
* @tparam Args
2021-01-12 23:48:43 +08:00
* @param start_date
* @param end_date
* @param time
2021-01-12 00:37:00 +08:00
*/
template <typename F, typename... Args>
2021-01-12 23:48:43 +08:00
void addFuncAtTimeEveryDay(Datetime start_date, Datetime end_date, TimeDelta time, F&& f,
Args&&... args) {
HKU_CHECK(!start_date.isNull() && !end_date.isNull(),
"Invalid start_date({}) or end_date({})!", start_date, end_date);
2021-01-12 00:37:00 +08:00
HKU_CHECK(time >= TimeDelta() && time <= TimeDelta(0, 23, 59, 59, 999, 999),
"Invalid time {}", time.repr());
2021-01-12 23:48:43 +08:00
Datetime start = start_date.startOfDay();
Datetime end = end_date.startOfDay();
HKU_CHECK(end >= start, "Invalid range of date! ({} - {})", start, end);
2021-01-12 00:37:00 +08:00
_addFunc(Datetime::min(), Datetime::max(), TimeDelta(-1), time,
std::numeric_limits<int>::max(), TimeDelta(), std::forward<F>(f),
std::forward<Args>(args)...);
}
2021-01-12 23:48:43 +08:00
/**
* ,
* @tparam F
* @tparam Args
* @param time
*/
template <typename F, typename... Args>
void addFuncAtTimeEveryDay(TimeDelta time, F&& f, Args&&... args) {
addFuncAtTimeEveryDay(Datetime::min(), Datetime::max(), time, std::forward<F>(f),
std::forward<Args>(args)...);
}
2021-01-09 00:11:16 +08:00
private:
2021-01-10 00:19:12 +08:00
void removeTimer(int id) {
delete m_timers[id];
m_timers.erase(id);
}
void detectThread() {
2021-01-09 00:11:16 +08:00
while (!m_stop) {
2021-01-11 00:22:08 +08:00
Datetime now = Datetime::now();
2021-01-09 00:11:16 +08:00
std::unique_lock<std::mutex> lock(m_mutex);
if (m_queue.empty()) {
m_cond.wait(lock);
continue;
}
2021-01-10 00:19:12 +08:00
IntervalS s = m_queue.top();
2021-01-17 21:28:16 +08:00
if (s.m_time_point == Datetime::min()) {
break; // 结束检测线程,用于 dll 能够安全退出因为atomic在dll退出时可能无效
}
2021-01-10 00:19:12 +08:00
TimeDelta diff = s.m_time_point - now;
if (diff > TimeDelta()) {
m_cond.wait_for(lock, std::chrono::duration<int64_t, std::micro>(diff.ticks()));
2021-01-09 00:11:16 +08:00
continue;
2021-01-10 00:19:12 +08:00
}
2021-01-10 17:41:06 +08:00
m_queue.pop();
auto timer_iter = m_timers.find(s.m_timer_id);
if (timer_iter == m_timers.end()) {
continue;
}
auto timer = timer_iter->second;
m_tg->submit(timer->m_func);
2021-01-11 00:22:08 +08:00
if (timer->m_repeat_num != std::numeric_limits<int>::max()) {
timer->m_repeat_num--;
}
2021-01-10 17:41:06 +08:00
if (timer->m_repeat_num <= 0) {
removeTimer(s.m_timer_id);
continue;
}
2021-01-12 00:37:00 +08:00
Datetime today = now.startOfDay();
s.m_time_point = timer->m_start_time >= TimeDelta() ? s.m_time_point + timer->m_duration
: s.m_time_point + TimeDelta(1);
2021-01-10 17:41:06 +08:00
if (timer->m_end_date != Datetime::max() &&
s.m_time_point > timer->m_end_date + timer->m_end_time) {
removeTimer(s.m_timer_id);
continue;
}
2021-01-12 00:37:00 +08:00
if (timer->m_start_time >= TimeDelta() && timer->m_start_time != timer->m_end_time &&
2021-01-10 17:41:06 +08:00
s.m_time_point > today + timer->m_end_time) {
s.m_time_point = today + timer->m_start_time + TimeDelta(1);
}
2021-01-12 23:48:43 +08:00
HKU_TRACE("s.m_time_point: {}", s.m_time_point.repr());
2021-01-10 17:41:06 +08:00
m_queue.push(s);
2021-01-10 00:19:12 +08:00
}
}
// 分配 timer_id
int getNewTimerId() {
int max_int = std::numeric_limits<int>::max();
HKU_WARN_IF_RETURN(m_timers.size() >= max_int, -1, "Timer queue is full!");
2021-01-10 17:41:06 +08:00
if (m_current_timer_id >= max_int) {
m_current_timer_id = 0;
} else {
m_current_timer_id++;
}
2021-01-10 00:19:12 +08:00
while (true) {
2021-01-10 17:41:06 +08:00
if (m_timers.find(m_current_timer_id) != m_timers.end()) {
if (m_current_timer_id >= max_int) {
m_current_timer_id = 0;
2021-01-10 00:19:12 +08:00
} else {
2021-01-10 17:41:06 +08:00
m_current_timer_id++;
2021-01-10 00:19:12 +08:00
}
} else {
break;
2021-01-09 00:11:16 +08:00
}
}
2021-01-10 17:41:06 +08:00
return m_current_timer_id;
2021-01-09 00:11:16 +08:00
}
private:
2021-01-10 00:19:12 +08:00
class Timer {
public:
void operator()() {
m_func();
}
Datetime m_start_date = Datetime::min().startOfDay(); // 允许执行的起始日期(包含该日期)
Datetime m_end_date = Datetime::max().startOfDay(); // 允许执行的终止日期(包含该日期)
2021-01-12 00:37:00 +08:00
/*
* m_start_time < TimeDelta(0), m_end_time
* m_duration
*/
2021-01-10 00:19:12 +08:00
TimeDelta m_start_time; // 允许执行的当日起始时间(包含该时间)
TimeDelta m_end_time; // 允许执行的当日结束时间(包含该时间)
TimeDelta m_duration; // 延迟时长或间隔时长
int m_repeat_num = 1; // 重复执行次数max标识无限循环
std::function<void()> m_func;
};
struct IntervalS {
Datetime m_time_point; // 执行的精确时间点
int m_timer_id = -1; // 对应的 Timer, 负数无效
bool operator<(const IntervalS& other) const {
return m_time_point > other.m_time_point;
}
};
2021-01-11 00:22:08 +08:00
template <typename F, typename... Args>
void _addFunc(Datetime start_date, Datetime end_date, TimeDelta start_time, TimeDelta end_time,
int repeat_num, TimeDelta duration, F&& f, Args&&... args) {
2021-01-12 00:37:00 +08:00
Datetime now = Datetime::now();
Datetime today = now.startOfDay();
HKU_CHECK(end_date >= today, "Invalid end_date {}, because today is {}", end_date, today);
if (end_date != Datetime::max()) {
HKU_CHECK(end_date + end_time >= now,
"Invalid param! You want end time is {}, but now is {}", end_date + end_time,
now);
}
Timer* timer = new Timer;
timer->m_start_date = start_date;
timer->m_end_date = end_date;
timer->m_start_time = start_time;
timer->m_end_time = end_time;
timer->m_repeat_num = repeat_num;
timer->m_duration = duration;
timer->m_func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
2021-01-11 00:22:08 +08:00
IntervalS s;
2021-01-12 00:37:00 +08:00
if (start_time < TimeDelta()) {
Datetime first_start_time = start_date + end_time;
if (first_start_time >= now) {
s.m_time_point = first_start_time;
} else {
HKU_CHECK(repeat_num > 1, "The time has expired! expect time {}, but now is {}",
first_start_time, now);
s.m_time_point = today + end_time;
if (s.m_time_point < now) {
s.m_time_point = s.m_time_point + TimeDelta(1);
}
}
} else {
s.m_time_point =
start_date >= today ? start_date + start_time + duration : now + duration;
if (timer->m_start_time != timer->m_end_time) {
Datetime point_date = s.m_time_point.startOfDay();
TimeDelta point = s.m_time_point - point_date;
if (point < timer->m_start_time) {
s.m_time_point = point_date + timer->m_start_time;
} else if (point > timer->m_end_time) {
s.m_time_point = point_date + timer->m_start_time + TimeDelta(1);
} else {
TimeDelta gap = point - timer->m_start_time;
if (gap % timer->m_duration != TimeDelta()) {
int x = int(gap / timer->m_duration) + 1;
s.m_time_point =
point_date + timer->m_start_time + timer->m_duration * double(x);
}
}
}
}
2021-01-11 00:22:08 +08:00
std::unique_lock<std::mutex> lock(m_mutex);
int id = getNewTimerId();
if (id < 0) {
2021-01-12 00:37:00 +08:00
delete timer;
2021-01-11 00:22:08 +08:00
lock.unlock();
HKU_THROW("Failed to get new id, maybe too timers!");
}
2021-01-12 00:37:00 +08:00
m_timers[id] = timer;
2021-01-11 00:22:08 +08:00
s.m_timer_id = id;
2021-01-12 00:37:00 +08:00
HKU_TRACE("s.m_time_point: {}", s.m_time_point.repr());
2021-01-11 00:22:08 +08:00
m_queue.push(s);
lock.unlock();
m_cond.notify_all();
}
2021-01-10 00:19:12 +08:00
private:
std::priority_queue<IntervalS> m_queue;
2021-01-09 00:11:16 +08:00
std::atomic_bool m_stop;
std::mutex m_mutex;
std::condition_variable m_cond;
2021-01-16 00:15:28 +08:00
std::thread m_detect_thread;
2021-01-09 00:11:16 +08:00
2021-01-10 00:19:12 +08:00
std::unordered_map<int, Timer*> m_timers;
int m_current_timer_id;
2021-01-14 22:44:34 +08:00
size_t m_work_num; // 任务执行线程池线程数量
2021-01-10 00:19:12 +08:00
std::unique_ptr<ThreadPool> m_tg;
}; // namespace hku
2021-01-09 00:11:16 +08:00
} // namespace hku