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

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 是一个非常方便和高效的工具。它可以帮助你简化任务调度和管理,并提高系统的可靠性和可维护性。

相关推荐
●VON15 小时前
从模型到价值:MLOps 工程体系全景解析
人工智能·学习·制造·von
好奇龙猫15 小时前
【人工智能学习-AI-MIT公开课第 18. 表示:分類、軌跡、過渡】
学习
hhcccchh16 小时前
学习vue第八天 Vue3 模板语法和内置指令 - 简单入门
前端·vue.js·学习
浩瀚地学16 小时前
【Java】异常
java·开发语言·经验分享·笔记·学习
Nan_Shu_61417 小时前
学习: Threejs (3)& Threejs (4)
学习
IT=>小脑虎18 小时前
2026版 Python零基础小白学习知识点【基础版详解】
开发语言·python·学习
李泽辉_19 小时前
深度学习算法学习(五):手动实现梯度计算、反向传播、优化器Adam
深度学习·学习·算法
星火开发设计19 小时前
C++ set 全面解析与实战指南
开发语言·c++·学习·青少年编程·编程·set·知识
坚持就完事了19 小时前
Linux的学习03:时间没有更新怎么解决
学习