* 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.
*/
#include "TimerThreadPool.h"
namespace omnistream {
TimerThreadPool::TimerThreadPool(size_t threads)
{
for (size_t i = 0; i < threads; ++i) {
workers_.emplace_back([this] {
while (!(stop_ && worker_tasks_.empty())) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex_);
worker_cv_.wait(lock, [this] { return stop_ || !worker_tasks_.empty(); });
if (stop_ && worker_tasks_.empty()) return;
task = std::move(worker_tasks_.front());
worker_tasks_.pop();
}
task();
}
});
}
scheduler_ = std::thread([this]() {
while (!stop_) {
std::unique_lock<std::mutex> lock(timer_mutex_);
if (timers_.empty()) {
timer_cv_.wait(lock, [this] { return stop_ || !timers_.empty(); });
}
if (stop_) break;
cleanCancelledTasks();
if (timers_.empty()) continue;
auto now = std::chrono::steady_clock::now();
auto task_wrapper = timers_.top();
if (task_wrapper.execute_time > now) {
timer_cv_.wait_until(lock, task_wrapper.execute_time);
} else {
timers_.pop();
if (task_wrapper.period_ms > 0) {
if (!cancelled_ids_.count(task_wrapper.id)) {
TimerTask next_task = task_wrapper;
next_task.execute_time += std::chrono::milliseconds(task_wrapper.period_ms);
timers_.push(next_task);
} else {
cancelled_ids_.erase(task_wrapper.id);
}
}
lock.unlock();
if (!isCancelled(task_wrapper.id)) {
{
std::lock_guard<std::mutex> queue_lock(queue_mutex_);
worker_tasks_.push(task_wrapper.func);
}
worker_cv_.notify_one();
}
}
}
});
}
TimerThreadPool::~TimerThreadPool()
{
{
std::lock_guard<std::mutex> lock1(queue_mutex_);
std::lock_guard<std::mutex> lock2(timer_mutex_);
stop_ = true;
}
timer_cv_.notify_all();
worker_cv_.notify_all();
if (scheduler_.joinable()) scheduler_.join();
for (std::thread& worker : workers_) {
if (worker.joinable()) worker.join();
}
}
void TimerThreadPool::cancel(TaskId id)
{
std::shared_ptr<Token> token_to_invalidate;
{
std::lock_guard<std::mutex> lock(tokens_mutex_);
auto it = task_tokens_.find(id);
if (it != task_tokens_.end()) {
token_to_invalidate = it->second;
task_tokens_.erase(it);
}
}
if (token_to_invalidate) {
token_to_invalidate->is_valid.store(false, std::memory_order_release);
}
{
std::lock_guard<std::mutex> lock(timer_mutex_);
cancelled_ids_.insert(id);
}
}
void TimerThreadPool::cleanCancelledTasks()
{
while (!timers_.empty()) {
auto& top = timers_.top();
if (cancelled_ids_.count(top.id)) {
auto id = top.id;
timers_.pop();
cancelled_ids_.erase(id);
} else {
break;
}
}
}
bool TimerThreadPool::isCancelled(TimerThreadPool::TaskId id)
{
std::lock_guard<std::mutex> lock(timer_mutex_);
auto it = cancelled_ids_.find(id);
if (it != cancelled_ids_.end()) {
cancelled_ids_.erase(it);
return true;
}
return false;
}
}