返回
基于C++11的线程池实现: 细枝末节暗藏玄机,初学者必读!
后端
2023-12-30 23:58:51
前段时间偶然在github上看到了一个非常精炼的C++11线程池实现。作者用不到100行的代码实现了一个简单的线程池,且使用了较多C++11的新特性。于是便想着自己也来动手看看,思路上基本是借鉴原版,在部分实现上做了些许调整。
线程池简介
线程池是一种管理线程的机制,它可以将线程集中起来,以便在需要时可以快速分配线程来执行任务。线程池可以提高应用程序的性能,因为它可以减少创建和销毁线程的开销。
C++11线程池实现
以下是用C++11实现的一个简单的线程池:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
// 线程池类
class ThreadPool {
public:
// 构造函数
ThreadPool(int num_threads) : num_threads_(num_threads) {
// 创建线程池中的线程
for (int i = 0; i < num_threads_; i++) {
threads_.push_back(std::thread([this] {
while (true) {
// 获取任务
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(mtx_);
// 如果任务队列为空,则等待任务
while (tasks_.empty()) {
cv_.wait(lock);
}
// 获取任务
task = std::move(tasks_.front());
// 从任务队列中移除任务
tasks_.pop();
}
// 执行任务
task();
}
}));
}
}
// 析构函数
~ThreadPool() {
// 停止线程池中的线程
{
std::unique_lock<std::mutex> lock(mtx_);
stop_ = true;
cv_.notify_all();
}
// 等待线程池中的线程退出
for (auto& thread : threads_) {
thread.join();
}
}
// 添加任务到线程池
void AddTask(std::function<void()> task) {
// 将任务添加到任务队列中
{
std::unique_lock<std::mutex> lock(mtx_);
tasks_.push(std::move(task));
// 通知线程池中的线程有任务可执行
cv_.notify_one();
}
}
private:
// 线程池中线程的数量
int num_threads_;
// 线程池中的线程
std::vector<std::thread> threads_;
// 任务队列
std::queue<std::function<void()>> tasks_;
// 互斥锁
std::mutex mtx_;
// 条件变量
std::condition_variable cv_;
// 停止标志
bool stop_ = false;
};
// 使用线程池
int main() {
// 创建一个线程池
ThreadPool thread_pool(4);
// 添加任务到线程池
for (int i = 0; i < 100; i++) {
thread_pool.AddTask([i] {
std::cout << "任务" << i << "正在执行\n";
});
}
return 0;
}
这个线程池实现使用了C++11的许多新特性,如lambda表达式、move语义和原子操作。这些特性可以提高线程池的性能和简化代码。
使用线程池的注意事项
在使用线程池时,需要注意以下几点:
- 线程池的大小应根据应用程序的实际需要来确定。如果线程池过大,可能会导致线程资源的浪费;如果线程池过小,可能会导致任务执行速度变慢。
- 线程池中的线程应尽量保持忙碌。如果线程池中的线程经常处于空闲状态,可能会导致线程资源的浪费。
- 线程池中的任务应尽量避免长时间运行。如果任务运行时间过长,可能会导致线程池中的其他任务无法及时执行。
使用范例
线程池可以用于各种并行计算场景。例如,可以使用线程池来处理图像处理、视频编码、数据分析等任务。
以下是一个使用线程池处理图像处理任务的示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <opencv2/opencv.hpp>
using namespace cv;
// 线程池类
class ThreadPool {
public:
// 构造函数
ThreadPool(int num_threads) : num_threads_(num_threads) {
// 创建线程池中的线程
for (int i = 0; i < num_threads_; i++) {
threads_.push_back(std::thread([this] {
while (true) {
// 获取任务
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(mtx_);
// 如果任务队列为空,则等待任务
while (tasks_.empty()) {
cv_.wait(lock);
}
// 获取任务
task = std::move(tasks_.front());
// 从任务队列中移除任务
tasks_.pop();
}
// 执行任务
task();
}
}));
}
}
// 析构函数
~ThreadPool() {
// 停止线程池中的线程
{
std::unique_lock<std::mutex> lock(mtx_);
stop_ = true;
cv_.notify_all();
}
// 等待线程池中的线程退出
for (auto& thread : threads_) {
thread.join();
}
}
// 添加任务到线程池
void AddTask(std::function<void()> task) {
// 将任务添加到任务队列中
{
std::unique_lock<std::mutex> lock(mtx_);
tasks_.push(std::move(task));
// 通知线程池中的线程有任务可执行
cv_.notify_one();
}
}
private:
// 线程池中线程的数量
int num_threads_;
// 线程池中的线程
std::vector<std::thread> threads_;
// 任务队列
std::queue<std::function<void()>> tasks_;
// 互斥锁
std::mutex mtx_;
// 条件变量
std::condition_variable cv_;
// 停止标志
bool stop_ = false;
};
// 图像处理任务
void ImageProcessingTask(Mat image) {
// 对图像进行处理
cvtColor(image, image, COLOR_BGR2GRAY);
GaussianBlur(image, image, Size(3, 3), 0);
Canny(image, image, 50, 100);
}
// 使用线程池处理图像处理任务
int main() {
// 创建一个线程池
ThreadPool thread_pool(4);
// 读取图像
Mat image = imread("image.jpg");
// 将图像处理任务添加到线程池
thread_pool.AddTask([image] {
ImageProcessingTask(image);
imwrite("processed_image.jpg", image);
});
return 0;
}
在这个示例中,我们使用线程池来处理图像处理任务。首先,我们创建一个线程池。然后,我们将图像处理任务添加到线程池。最后,我们等待线程池中的线程完成任务。
结语
线程池是一种非常有用的工具,它可以提高应用程序的性能。C++11为线程池的实现提供了许多新的特性,这些特性可以使线程池的实现更加简单和高效。