文章目录
在定时器设计中,使用线程池来执行定时任务可以有效提高程序的性能和可扩展性。线程池能够避免频繁创建和销毁线程的开销,并且通过重用线程来提高任务调度的效率。本文将介绍如何结合线程池和定时器来实现一个高效的定时任务调度系统。
我们将基于两种常见的定时器实现方式——优先队列 和 时间轮,使用线程池来执行定时任务,并分析每种实现方式的优缺点。
1. 线程池概述
线程池是一种管理多个线程的机制,避免了每次执行任务时创建和销毁线程的开销。线程池会预先创建一定数量的线程,并将任务提交给线程池执行。线程池中的线程会从任务队列中取出任务并执行,直到任务完成。
线程池的基本特点:
- 线程复用:线程池中的线程在任务执行完成后不会退出,而是继续等待下一个任务。
- 任务排队:任务被放入任务队列,线程池中的线程按顺序执行任务。
- 线程池大小控制:可以设置线程池的大小,避免线程过多或过少导致系统性能下降。
2. 使用线程池的优先队列定时器实现
在优先队列定时器中,使用线程池来执行定时任务,可以提高任务的执行效率。我们将在定时器任务到期时将任务提交到线程池执行,线程池会负责管理任务的执行。
2.1 优先队列定时器实现
#include <iostream>
#include <queue>
#include <functional>
#include <chrono>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>
using namespace std;
using namespace std::chrono;
// 定时任务结构体
struct TimerTask {
steady_clock::time_point expiration_time; // 任务到期时间
function<void()> callback; // 任务回调函数
bool repeat; // 是否是周期性任务
milliseconds interval; // 周期性任务间隔
bool operator>(const TimerTask& other) const {
return expiration_time > other.expiration_time;
}
};
// 线程池实现
class ThreadPool {
private:
vector<thread> workers; // 线程池中的工作线程
queue<function<void()>> tasks; // 任务队列
mutex tasks_mutex; // 任务队列的互斥锁
condition_variable cv; // 条件变量
bool stop; // 是否停止线程池
public:
ThreadPool(size_t num_threads) : stop(false) {
for (size_t i = 0; i < num_threads; ++i) {
workers.emplace_back([this] {
while (true) {
function<void()> task;
{
unique_lock<mutex> lock(tasks_mutex);
cv.wait(lock, [this] {
return !tasks.empty() || stop; });
if (stop && tasks.empty()) return; // 如果线程池被停止且任务队列为空,则退出
task = move(tasks.front());
tasks.pop();
}</