如何创建通用C++调度类,实现多类方法的定时线程执行及单实例复用?
方案可行性与实现思路
这个方案完全可行,而且完全可以用单个GenericScheduler实例管理所有三个任务,不需要创建多个实例。下面是具体的实现思路和关键细节:
核心原理:统一不同签名的成员函数
C++的std::function、lambda表达式和std::bind可以轻松将参数不同的run方法包装成调度器能处理的统一签名(比如无参void()函数)。不管Class1::run是带int+string参数,还是Class2::run带double参数,都能被封装成相同类型的可调用对象,供调度器统一管理。
单个GenericScheduler实例的实现方式
让GenericScheduler内部维护一个任务列表,每个任务项包含以下信息:
- 包装后的目标可调用函数
- 执行间隔
- CPU亲和性配置
- 调度优先级
- 对应的线程对象
通过模板方法addTask接收任意类的成员函数、参数及调度配置,自动完成函数绑定、线程创建和调度参数设置。
示例代码实现
#include <functional> #include <thread> #include <vector> #include <chrono> #include <atomic> #include <pthread.h> // Linux平台,Windows需替换为对应API class GenericScheduler { private: struct Task { std::function<void()> func; std::chrono::milliseconds interval; cpu_set_t affinity; int priority; std::thread thread; std::atomic<bool> stopFlag{false}; }; std::vector<Task> tasks; void taskLoop(Task& task) { // 设置CPU亲和性(Linux示例) pthread_setaffinity_np(task.thread.native_handle(), sizeof(cpu_set_t), &task.affinity); // 设置调度优先级(Linux SCHED_FIFO策略) struct sched_param param; param.sched_priority = task.priority; pthread_setschedparam(task.thread.native_handle(), SCHED_FIFO, ¶m); while (!task.stopFlag.load()) { try { task.func(); } catch (const std::exception& e) { // 处理任务执行异常,避免线程崩溃 // 比如记录日志:std::cerr << "Task error: " << e.what() << std::endl; } std::this_thread::sleep_for(task.interval); } } public: template <typename ClassType, typename... Args> void addTask(ClassType* obj, void (ClassType::*runFunc)(Args...), std::chrono::milliseconds interval, cpu_set_t affinity, int priority, Args... args) { // 绑定对象与参数,包装为无参可调用函数 auto wrappedFunc = [obj, runFunc, args...]() { (obj->*runFunc)(args...); }; tasks.emplace_back(); auto& newTask = tasks.back(); newTask.func = wrappedFunc; newTask.interval = interval; newTask.affinity = affinity; newTask.priority = priority; newTask.thread = std::thread(&GenericScheduler::taskLoop, this, std::ref(newTask)); } // 停止所有任务并等待线程结束 void stopAll() { for (auto& task : tasks) { task.stopFlag.store(true); } waitAll(); } void waitAll() { for (auto& task : tasks) { if (task.thread.joinable()) { task.thread.join(); } } } ~GenericScheduler() { stopAll(); } }; // 测试用类 class Class1 { public: void run(int id, const std::string& msg) { // 业务逻辑示例 // std::cout << "Class1 run: id=" << id << ", msg=" << msg << std::endl; } }; class Class2 { public: void run(double value) { // 业务逻辑示例 // std::cout << "Class2 run: value=" << value << std::endl; } }; class Class3 { public: void run() { // 业务逻辑示例 // std::cout << "Class3 run" << std::endl; } }; int main() { GenericScheduler scheduler; Class1 c1; Class2 c2; Class3 c3; // 配置CPU亲和性(绑定到不同CPU核心) cpu_set_t cpuSet1, cpuSet2, cpuSet3; CPU_ZERO(&cpuSet1); CPU_SET(0, &cpuSet1); CPU_ZERO(&cpuSet2); CPU_SET(1, &cpuSet2); CPU_ZERO(&cpuSet3); CPU_SET(2, &cpuSet3); // 添加三个不同的任务到同一个调度器实例 scheduler.addTask(&c1, &Class1::run, std::chrono::milliseconds(1000), cpuSet1, 10, 1001, "hello"); scheduler.addTask(&c2, &Class2::run, std::chrono::milliseconds(500), cpuSet2, 15, 3.1415); scheduler.addTask(&c3, &Class3::run, std::chrono::milliseconds(2000), cpuSet3, 5); // 主线程等待(实际项目中可能是其他逻辑) std::this_thread::sleep_for(std::chrono::seconds(10)); scheduler.stopAll(); return 0; }
关键注意事项
- 平台兼容性:示例用了Linux的pthread API处理CPU亲和性和优先级,Windows平台需要替换为
SetThreadAffinityMask、SetThreadPriority等API,建议用条件编译处理跨平台逻辑。 - 异常安全:在任务循环中捕获异常,避免单个任务崩溃导致线程退出。
- 优雅退出:添加原子停止标志,允许外部触发任务停止,避免强制终止线程。
- 可扩展性:这个架构很容易扩展,比如添加动态调整任务间隔/优先级、任务启停控制、线程池模式(当任务数量较多时)等功能。
内容的提问来源于stack exchange,提问作者user3746381
相关产品推荐
相关产品推荐

