- 使用std::priority_queue容器自动在加入时排序
- 线程池可以动态变化
- 周期调度任务执行于线程池
- 定时时间到达任务排队到线程池执行
ThreadPool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <atomic>
#include <memory>
#include <chrono>
#include <stdexcept>
#include <algorithm>
#include <list>
#include "LogLib.h"
namespace TaskScheduler
{
const size_t CORE_THREADS = 2;
const size_t MAX_THREADS = 8;
const size_t MAX_QUEUE_SIZE = 8;
const size_t THREAD_RECYCLE_TIME = 60;
using taskJob = std::function<void()>;
class ThreadPool
{
public:
ThreadPool(size_t coreThreads = CORE_THREADS,
size_t maxThreads = MAX_THREADS,
size_t maxQueueSize = MAX_QUEUE_SIZE,
size_t idleTime = THREAD_RECYCLE_TIME)
: m_coreThreads(std::max(CORE_THREADS, coreThreads)),
m_maxThreads(std::max(MAX_THREADS, maxThreads)),
m_maxQueueSize(std::max(MAX_QUEUE_SIZE, maxQueueSize)),
m_idleTime(std::max(THREAD_RECYCLE_TIME, idleTime)),
m_stop(false)
{
// 启动核心线程
for (size_t i = 0; i < coreThreads; ++i)
{
AddThread();
}
}
~ThreadPool()
{
Shutdown(); // 在析构函数中调用 Shutdown 以确保线程池关闭。
}
// 提交任务,并返回 future 以获取结果
template <class F, class... Args>
auto Enqueue(F &&f, Args &&...args) -> std::future<decltype(f(args...))>
{
using return_type = decltype(f(args...));
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(m_mtx);
// 如果线程池已停止,则不再接受新任务
if (m_stop.load())
{
return res;
}
// 如果队列已满且线程未达最大值,则添加新线程
if (m_tasks.size() >= m_maxQueueSize)
{
if (m_threads.size() < m_maxThreads)
{
AddThread(); // 动态添加新线程
}
else
{
// 调用者运行策略
lock.unlock(); // 解锁避免死锁
(*task)(); // 在调用线程中执行任务
return res;
}
}
// 将任务添加到任务队列
m_tasks.emplace([task]()
{ (*task)(); });
}
m_cv.notify_one(); // 唤醒一个线程来处理任务
return res;
}
// 关闭线程池,并等待所有线程完成
void Shutdown()
{
{
std::lock_guard<std::mutex> lock(m_mtx);
m_stop.store(true); // 标志线程池停止接受新任务
}
m_cv.notify_all(); // 唤醒所有线程
// 等待所有线程完成并退出
for (auto &thread : m_threads)
{
if (thread.joinable())
{
thread.join();
}
}
}
private:
// 添加新线程到线程池
void AddThread()
{
m_threads.emplace_back([this]
{
while (true) {
taskJob task;
{
std::unique_lock<std::mutex> lock(m_mtx);
// 等待任务或线程池关闭通知,支持空闲超时回收
if (!m_cv.wait_for(lock, m_idleTime,
[this] { return m_stop.load() || !m_tasks.empty(); })) {
// 保留核心线程
if (m_coreThreads >= m_threads.size()) continue;
// 如果线程空闲超过 idleTime,则回收该线程
lock.unlock(); // 解锁避免死锁
Enqueue ([this](std::thread::id self_id){
auto it = std::find_if(m_threads.begin(), m_threads.end(),
[self_id](const std::thread &t)
{
return t.get_id() == self_id;
});
if (it != m_threads.end())
{
TRACE_LOG("Stopping and removing thread");
if (it->joinable())
{
it->join();
}
m_threads.erase(it);
}
}, std::this_thread::get_id());
return;
}
if (m_stop.load() && m_tasks.empty()) {
return; // 如果线程池停止且任务为空,则退出
}
// 从任务队列中取出任务
task = std::move(m_tasks.front());
m_tasks.pop();
}
task(); // 执行任务
} });
}
size_t m_coreThreads; // 核心线程数
size_t m_maxThreads; // 最大线程数
size_t m_maxQueueSize; // 任务队列最大长度
std::chrono::seconds m_idleTime; // 空闲线程的回收时间
std::list<std::thread> m_threads; // 线程列表
std::queue<taskJob> m_tasks; // 任务队列
std::mutex m_mtx; // 互斥锁保护任务队列和线程列表
std::condition_variable m_cv; // 条件变量用于线程同步
std::atomic<bool> m_stop; // 标志线程池是否停止
};
}
#endif
TaskScheduler.h
#ifndef __INCTaskSchedulerh
#define __INCTaskSchedulerh
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
#include <atomic>
#include <unordered_map>
#include <cstring>
#include "ThreadPool.h"
namespace TaskScheduler
{
const int64_t TIMES_FOREVER = -1;
using milliseconds = std::chrono::milliseconds;
using qJob = std::function<void(void *)>;
const int MAX_TASK_NAME_LEN = 32;
// 定义任务结构
typedef struct Task
{
char name[MAX_TASK_NAME_LEN]; // 任务名称
qJob taskFunc; // 任务函数
void *arg; // 任务参数
std::chrono::steady_clock::time_point executeTime; // 执行时间
milliseconds interval; // 定时间隔(毫秒)(如果是周期任务,设置该值)
bool periodic; // 是否周期任务
bool cancelled; // 标记任务是否被取消
int64_t execTimes; // 执行次数
Task(bool periodic) : periodic(periodic), cancelled(false)
{
::memset(name, 0, MAX_TASK_NAME_LEN);
}
} TASK;
using TASK_ID = std::shared_ptr<TASK>;
// 用于任务的排序,按照执行时间排序
struct TaskComparator
{
bool operator()(const TASK_ID a, const TASK_ID b) const
{
return a->executeTime < b->executeTime;
}
};
class TaskScheduler
{
public:
TaskScheduler();
~TaskScheduler();
void Init();
// 添加单次执行任务
TASK_ID AddOneTimeTask(const char *name,
const qJob &taskFunc,
void *arg = nullptr,
milliseconds delay = std::chrono::seconds(5));
// 添加周期性任务
TASK_ID AddPeriodicTask(const char *name,
const qJob &taskFunc,
void *arg = nullptr,
milliseconds interval = std::chrono::seconds(5),
int64_t times = 1);
// 终止任务
bool RemoveTaskById(TASK_ID taskId);
private:
std::priority_queue<TASK_ID,
std::vector<TASK_ID>,
TaskComparator>
m_taskQueue; // 优先队列,按执行时间排序任务
std::mutex m_mtx; // 保护任务队列的互斥锁
std::condition_variable m_cv; // 条件变量,用于通知任务调度
std::atomic<bool> m_stop; // 控制调度器停止的标志
std::shared_ptr<ThreadPool> m_pool; // 线程池
// 工作线程函数
void Worker();
TASK_ID PrepareTask(TASK_ID task, const char *name,
const qJob &taskFunc,
void *param,
milliseconds interval,
int64_t times);
};
}
#endif
TaskScheduler.cpp
#include "TaskScheduler.h"
namespace TaskScheduler
{
TaskScheduler::TaskScheduler() : m_stop(false)
{
m_pool = std::make_shared<ThreadPool>();
}
TaskScheduler::~TaskScheduler()
{
{
std::lock_guard<std::mutex> lock(m_mtx);
m_stop = true;
}
m_cv.notify_all();
}
void TaskScheduler::Init()
{
m_pool->Enqueue([this]()
{
this->Worker(); // 线程池异步执行调度任务
});
}
TASK_ID TaskScheduler::PrepareTask(TASK_ID task, const char *name,
const qJob &taskFunc,
void *param,
milliseconds interval,
int64_t times)
{
::strncpy(task->name, name, MAX_TASK_NAME_LEN - 1);
task->arg = param;
task->taskFunc = taskFunc;
task->executeTime = std::chrono::steady_clock::now() + interval;
task->interval = interval;
task->execTimes = times;
{
std::lock_guard<std::mutex> lock(m_mtx);
m_taskQueue.push(task);
m_cv.notify_one();
}
return task;
}
// 添加单次执行任务
TASK_ID TaskScheduler::AddOneTimeTask(const char *name,
const qJob &taskFunc,
void *param,
milliseconds delay)
{
return PrepareTask(std::make_shared<TASK>(false), name, taskFunc,
param, delay, 1);
}
// 添加周期性任务
TASK_ID TaskScheduler::AddPeriodicTask(const char *name,
const qJob &taskFunc,
void *param,
milliseconds interval,
int64_t times)
{
return PrepareTask(std::make_shared<TASK>(true), name, taskFunc,
param, interval, times);
}
// 终止任务,根据任务ID将任务标记为已取消
bool TaskScheduler::RemoveTaskById(TASK_ID taskId)
{
std::lock_guard<std::mutex> lock(m_mtx);
m_cv.notify_one();
return taskId->cancelled = true;
}
// 工作线程函数
void TaskScheduler::Worker()
{
while (!m_stop)
{
std::unique_lock<std::mutex> lock(m_mtx);
if (m_taskQueue.empty())
{
m_cv.wait(lock); // 如果任务队列为空,阻塞等待任务到来
}
else
{
auto now = std::chrono::steady_clock::now();
auto nextTask = m_taskQueue.top(); // 获取最早的任务
// 如果任务处于未取消且执行时间未到达
if (!nextTask->cancelled && (now < nextTask->executeTime))
{
// 等待直到任务的执行时间或有新任务到来
m_cv.wait_until(lock, nextTask->executeTime);
continue;
}
m_taskQueue.pop(); // 从队列中移除任务
// 如果任务被取消,则跳过执行
if (nextTask->cancelled)
{
// 打印任务已取消的消息,并释放任务结构
TRACE_LOG("Task %s has been cancelled.\n", nextTask->name);
continue;
}
// 将任务提交给线程池异步执行
m_pool->Enqueue([](TASK_ID pTask)
{
// 打印任务名称
TRACE_LOG("Task %s is running.\n", pTask->name);
pTask->taskFunc(pTask->arg); // 执行任务
},
nextTask);
// 如果是周期性任务,重新计算执行时间并放回队列
if (nextTask->periodic &&
((nextTask->execTimes == TIMES_FOREVER) ||
(--nextTask->execTimes != 0)))
{
// 如果是周期性任务,重新计算执行时间并放回队列
nextTask->executeTime =
std::chrono::steady_clock::now() + nextTask->interval;
m_taskQueue.push(std::move(nextTask));
}
}
}
}
}