线程池学习(七)实现定时(调度)线程池

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 的场景:

  1. 定时任务调度:ScheduledThreadPool 可以用于执行在固定时间间隔内运行的任务。例如,定期备份数据、清理临时文件、定时发送邮件等。

  2. 任务调度器:ScheduledThreadPool 可以用作任务调度器,用于安排并执行后续任务。例如,你可以在程序启动后安排一些初始化任务执行,或者在程序结束前执行一些清理任务。

  3. 心跳任务:ScheduledThreadPool 可以用于执行心跳任务,即周期性地检测系统状态或发送心跳信号。例如,检查网络连接、检测硬件设备的状态等。

  4. 定时数据处理:ScheduledThreadPool 可以用于定时处理一些数据任务,例如在特定时间点对数据库进行优化、对日志进行归档等。

总之,如果你需要按照特定的时间间隔或时间点执行任务,ScheduledThreadPool 是一个非常方便和高效的工具。它可以帮助你简化任务调度和管理,并提高系统的可靠性和可维护性。

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习