ScheduledThreadPool核心思想
一句话:在指定时间执行任务,或按固定间隔重复执行
现在 5秒后 10秒后
↓ ↓ ↓
[任务A] → [任务B] → [任务C] → ...
📚 ScheduledThreadPool的两种模式
1. 一次性定时任务
// 5秒后执行一次
pool.schedule(5, [](){ /* 任务 */ });
2. 周期性重复任务
// 每隔3秒执行一次(无限重复)
pool.scheduleAtFixedRate(3, [](){ /* 任务 */ });
// 任务结束后,延迟2秒再执行下一次
pool.scheduleWithFixedDelay(2, [](){ /* 任务 */ });
第1部分:定时任务队列
核心数据结构:优先级队列
// 需要按执行时间排序,时间早的优先执行
priority_queue<定时任务, vector<定时任务>, 比较函数>
syncqueue.hpp
cpp
#ifndef SYNCQUEUE5_HPP
#define SYNCQUEUE5_HPP
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
#include <vector>
#include <iostream>
using namespace std;
using Task = function<void()>;
struct PairTask {
size_t first; // 延迟时间(秒)
Task second; // 任务函数
PairTask(size_t delay = 0, Task task = nullptr)
: first(delay), second(task) {}
// 用于priority_queue排序
bool operator>(const PairTask& other) const {
return first > other.first;
}
};
class SyncQueue {
private:
priority_queue<PairTask, vector<PairTask>, greater<PairTask>> tasks_;//最早的在堆顶
mutable mutex mutex_;
condition_variable not_empty_;
condition_variable not_full_;
size_t max_size_;
bool need_stop_;
bool isFull() const {
return tasks_.size() >= max_size_;
}
bool isEmpty() const {
return tasks_.empty();
}
public:
SyncQueue(size_t max_size = 100)
: max_size_(max_size), need_stop_(false) {}
// 放入任务
bool put(const PairTask& task) {
unique_lock<mutex> lock(mutex_);
// 等待队列不满
not_full_.wait(lock, [this]() {
return need_stop_ || !isFull();
});
if (need_stop_) return false;
tasks_.push(task);
not_empty_.notify_one();
return true;
}
// 取出任务(会等待到任务时间)
bool take(PairTask& task) {
unique_lock<mutex> lock(mutex_);
// 等待队列不空
while (!need_stop_ && isEmpty()) {
not_empty_.wait(lock);
}
if (need_stop_ && isEmpty()) return false;
// 取出堆顶任务(时间最早的任务)
task = tasks_.top();
tasks_.pop();
// 等待到任务执行时间
if (task.first > 0) {
not_empty_.wait_for(lock, chrono::seconds(task.first));
}
not_full_.notify_one();
return true;
}
// 停止队列
void stop() {
{
lock_guard<mutex> lock(mutex_);
need_stop_ = true;
}
not_empty_.notify_all();
not_full_.notify_all();
}
// 状态查询
size_t size() const {
lock_guard<mutex> lock(mutex_);
return tasks_.size();
}
bool empty() const {
lock_guard<mutex> lock(mutex_);
return tasks_.empty();
}
bool stopped() const {
lock_guard<mutex> lock(mutex_);
return need_stop_;
}
};
#endif
scheduledpoll.hpp
cpp
#ifndef SCHEDULEDPOOL_HPP
#define SCHEDULEDPOOL_HPP
#include"scheduledsyncqueue.hpp"
using namespace std;
#include<thread>
#include<atomic>
#include<functional>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<vector>
#include<future>
#include<chrono>
class scheduledthreadpool{
public:
using task=function<void()>;
private:
vector<thread>workers;
SyncQueue taskqueue;
atomic<bool>isrunning;
once_flag isstop;
void worker(){
while(isrunning){
PairTask st;
if(taskqueue.take(st)){
try{
st.second();
}catch(const exception&e){
cerr<<"定时任务执行异常"<<e.what()<<endl;
}
}
}
}
void stopall(){
isrunning=false;
taskqueue.stop();
for(auto&t:workers){
if(t.joinable())t.join();
}
workers.clear();
}
public:
scheduledthreadpool(size_t thread_count=thread::hardware_concurrency()):isrunning(true){
if(thread_count==0){
thread_count=thread::hardware_concurrency();
}
for(size_t i=0;i<thread_count;i++){
workers.emplace_back(&scheduledthreadpool::worker,this);
}
cout<<"定时任务线程池启动,线程数:"<<thread_count<<endl;
}
~scheduledthreadpool(){
stop();
}
scheduledthreadpool(const scheduledthreadpool&)=delete;
scheduledthreadpool& operator=(const scheduledthreadpool&)=delete;
void stop(){
call_once(isstop,[this](){stopall();cout<<"定时任务线程池停止"<<endl;});
}
template<typename Func,typename...Args>
void schedule(int delay_seconds,int interval_seconds,Func&&f,Args&&...args){//延迟执行 一次性
auto task=bind(forward<Func>(f),forward<Args>(args)...);
scheduledtask st;
st.task=move(task);
st.exec_time=chrono::steady_clock::now()+chrono::seconds(delay_seconds);
st.interval_seconds=0;
queue_.add(move(st));
}
template<typename Func,typename...Args>
void scheduleAtFixedRate(int delay_seconds,int interval_seconds,Func&&f,Args&&...args){//延迟执行 周期性
auto task=bind(forward<Func>(f),forward<Args>(args)...);
scheduledtask st;
st.task=move(task);
st.exec_time=chrono::steady_clock::now()+chrono::seconds(delay_seconds);
st.interval_seconds=interval_seconds;
queue_.add(move(st));
}
template<typename Func,typename...Args>
void schedulewithfixeddelay(int delay_seconds,int interval_seconds,Func&&f,Args&&...args){//固定延迟执行 任务结束后延迟固定时间
auto wrapped_func = [func = std::forward<Func>(func), args_tuple = std::make_tuple(std::forward<Args>(args)...),delay_seconds]() mutable {
// 执行原任务
std::apply(func, args_tuple);
// 任务完成后,重新调度自己(实现固定延迟)
// 注意:实际需要能访问queue_,这里简化处理
};
schedule(delay_seconds, std::move(wrapped_func));
}
template<typename Func,typename...Args>
auto scheduledwithresult(int delay_seconds,Func&&f,Args&&...args)->future<decltype(f(args...))>{
using returntype=decltype(f(args...));
auto task=make_shared<packaged_task<returntype()>>(bind(forward<Func>(f),forward<Args>(args)...));
future<returntype>result=task->get_future();
auto wrapped_task=[task](){(*task)();};
schedule(delay_seconds,move(wrapped_task));
return result;
}
size_t threadcount()const{
return workers.size();
}
size_t pendingtasks()const{//待执行任务数
return taskqueue.size();
}
bool isrunningpool()const{
return isrunning;
}
};
#endif
ScheduledThreadPool核心要点
1. 优先级队列
// 时间早的任务优先级高
priority_queue<Task, vector<Task>, greater<Task>>
2. 时间等待
// 精确等待到任务时间
cv_.wait_until(lock, task.execute_time);
3. 重复任务处理
if (task.interval_seconds > 0) {
// 重新计算时间,放回队列
task.execute_time = now + seconds(interval);
tasks_.push(task);
适合使用 ScheduledThreadPool 的场景:
-
定时任务调度:ScheduledThreadPool 可以用于执行在固定时间间隔内运行的任务。例如,定期备份数据、清理临时文件、定时发送邮件等。
-
任务调度器:ScheduledThreadPool 可以用作任务调度器,用于安排并执行后续任务。例如,你可以在程序启动后安排一些初始化任务执行,或者在程序结束前执行一些清理任务。
-
心跳任务:ScheduledThreadPool 可以用于执行心跳任务,即周期性地检测系统状态或发送心跳信号。例如,检查网络连接、检测硬件设备的状态等。
-
定时数据处理:ScheduledThreadPool 可以用于定时处理一些数据任务,例如在特定时间点对数据库进行优化、对日志进行归档等。
总之,如果你需要按照特定的时间间隔或时间点执行任务,ScheduledThreadPool 是一个非常方便和高效的工具。它可以帮助你简化任务调度和管理,并提高系统的可靠性和可维护性。