* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#ifndef OMNISTREAM_TIMERTHREADPOOL_H
#define OMNISTREAM_TIMERTHREADPOOL_H
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
#include <atomic>
#include <unordered_set>
namespace omnistream {
class TimerThreadPool {
public:
using TaskId = uint64_t;
static TimerThreadPool* GetTimerThreadPoolInstance()
{
static TimerThreadPool instance;
return &instance;
}
TimerThreadPool(size_t threads = 1);
~TimerThreadPool();
template <class F, class... Args>
TaskId addDelayedTask(unsigned int delay_ms, F&& f, Args&&... args)
{
return submitTask(delay_ms, 0, std::forward<F>(f), std::forward<Args>(args)...);
}
template <class F, class... Args>
TaskId addPeriodicTask(unsigned int interval_ms, F&& f, Args&&... args)
{
return submitTask(interval_ms, interval_ms, std::forward<F>(f), std::forward<Args>(args)...);
}
void cancel(TaskId id);
private:
struct Token {
std::atomic<bool> is_valid{true};
};
struct TimerTask {
std::chrono::steady_clock::time_point execute_time;
std::function<void()> func;
TaskId id;
unsigned int period_ms;
std::shared_ptr<Token> token;
bool operator<(const TimerTask& other) const
{
return execute_time > other.execute_time;
}
};
template <class F, class... Args>
TaskId submitTask(unsigned int delay_ms, unsigned int period_ms, F&& f, Args&&... args)
{
TaskId id = next_task_id_++;
auto token = std::make_shared<Token>();
{
std::lock_guard<std::mutex> lock(tokens_mutex_);
task_tokens_[id] = token;
}
auto task_func = [token, f = std::bind(std::forward<F>(f), std::forward<Args>(args)...)]() {
if (token->is_valid.load(std::memory_order_acquire)) {
f();
}
};
auto execute_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(delay_ms);
{
std::lock_guard<std::mutex> lock(timer_mutex_);
timers_.push({execute_time, task_func, id, period_ms, token});
}
timer_cv_.notify_one();
return id;
}
void cleanCancelledTasks();
bool isCancelled(TaskId id);
std::vector<std::thread> workers_;
std::queue<std::function<void()>> worker_tasks_;
std::mutex queue_mutex_;
std::condition_variable worker_cv_;
std::thread scheduler_;
std::priority_queue<TimerTask> timers_;
std::mutex timer_mutex_;
std::condition_variable timer_cv_;
std::atomic<bool> stop_;
std::atomic<TaskId> next_task_id_;
std::unordered_set<TaskId> cancelled_ids_;
std::unordered_map<TaskId, std::shared_ptr<Token>> task_tokens_;
mutable std::mutex tokens_mutex_;
};
}
#endif