在 C++ 中,线程池是一种用于管理和复用多个线程的设计模式,可以有效地提高程序的性能,特别是在需要频繁创建和销毁线程时。C++11 引入了许多多线程相关的库,使得实现线程池变得相对简单。
一、线程池的定义
#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <condition_variable>
#include <future>
#include <atomic>
class ThreadPool {
public:
ThreadPool(size_t numThreads);
~ThreadPool();
template<class F>
auto enqueue(F&& f) -> std::future<typename std::result_of<F()>::type>;
private:
std::vector<std::thread> workers; // 工作线程
std::queue<std::function<void()>> tasks; // 任务队列
std::mutex queueMutex; // 保护任务队列的互斥锁
std::condition_variable condition; // 条件变量
bool stop; // 停止标志
};
// 构造函数
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
for (;;) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queueMutex);
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty()) {
return; // 如果停止并且任务队列为空,退出线程
}
task = std::move(this->tasks.front());
this->tasks.pop();
}
task(); // 执行任务
}
});
}
}
// 析构函数
ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true; // 设置停止标志
}
condition.notify_all(); // 唤醒所有线程
for (std::thread &worker : workers) {
worker.join(); // 等待所有线程结束
}
}
// 向线程池添加任务
template<class F>
auto ThreadPool::enqueue(F&& f) -> std::future<typename std::result_of<F()>::type> {
using return_type = typename std::result_of<F()>::type;
auto task = std::make_shared<std::packaged_task<return_type()>>(std::forward<F>(f));
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queueMutex);
// 不允许在停止状态下添加任务
if (stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks.emplace([task]() { (*task)(); }); // 将任务添加到队列
}
condition.notify_one(); // 唤醒一个等待线程
return res; // 返回 future
}
二、使用线程池
#include <iostream>
#include <chrono>
#include "ThreadPool.h" // 假设 ThreadPool 类在这个头文件中定义
int main() {
ThreadPool pool(4); // 创建一个线程池,包含 4 个线程
// 提交一些任务
std::vector<std::future<void>> futures;
for (int i = 0; i < 10; ++i) {
futures.emplace_back(pool.enqueue([i] {
std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟任务执行
}));
}
// 等待所有任务完成
for (auto& future : futures) {
future.get(); // 获取结果,等待任务完成
}
return 0;
}
三、说明
-
ThreadPool 类:
- 该类包含一个线程池的实现,允许用户提交任务并在后台线程中执行。
- 使用
std::queue
存储任务,使用std::mutex
和std::condition_variable
进行线程同步。 - 提供
enqueue
方法来添加任务,并返回一个std::future
对象,以便用户可以等待任务完成并获取结果。
-
使用示例:
- 创建一个包含 4 个线程的线程池。
- 使用
enqueue
方法提交 10 个任务,每个任务在不同的线程中运行,并输出当前线程 ID。 - 使用
future.get()
等待所有任务完成。
四、总结
这个简单的线程池实现可以处理并发任务,减少线程创建和销毁的开销。可以根据需要扩展功能,例如添加任务优先级、动态调整线程数等。使用线程池可以有效提高程序的性能,尤其是在需要处理大量短时间运行的任务时