在C++里实现线程池,主要有以下几个关键步骤:
- 任务队列:创建一个队列来存放待执行的任务。可以用C++标准库中的
std::queue
结合std::function
来实现,其作用是存储用户提交的任务。 - 工作线程集合:借助
std::vector
和std::thread
创建一个线程集合。这些线程会不断地从任务队列中获取任务并执行。 - 同步机制:运用
std::mutex
和std::condition_variable
来保证线程安全,实现线程间的同步。当任务队列为空时,工作线程会进入等待状态;当有新任务加入队列或者线程池需要关闭时,线程会被唤醒。 - 线程管理:实现线程池的初始化、任务提交、线程池关闭等功能。
下面是线程池的核心代码逻辑:
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
class ThreadPool {
public:
// 构造函数,创建指定数量的工作线程
ThreadPool(size_t numThreads);
// 析构函数,关闭线程池
~ThreadPool();
// 提交任务到线程池
template<class F>
void enqueue(F&& task);
// 禁止拷贝构造和赋值
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool&) = delete;
private:
// 工作线程集合
std::vector<std::thread> workers;
// 任务队列
std::queue<std::function<void()>> tasks;
// 同步原语
std::mutex queueMutex;
std::condition_variable condition;
// 线程池状态
std::atomic<bool> stop;
// 工作线程函数
void workerThread();
};
// 构造函数实现
ThreadPool::ThreadPool(size_t numThreads) : stop(false) {
// 创建指定数量的工作线程
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
this->workerThread();
});
}
}
// 工作线程函数实现
void ThreadPool::workerThread() {
while (true) {
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();
}
}
// 任务提交函数实现
template<class F>
void ThreadPool::enqueue(F&& task) {
{
// 加锁访问任务队列
std::unique_lock<std::mutex> lock(queueMutex);
// 线程池关闭后禁止提交新任务
if (stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
// 将任务加入队列
tasks.emplace(std::forward<F>(task));
}
// 通知一个等待的线程
condition.notify_one();
}
// 析构函数实现
ThreadPool::~ThreadPool() {
{
// 加锁设置停止标志
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
// 通知所有线程
condition.notify_all();
// 等待所有线程完成
for (std::thread& worker : workers) {
worker.join();
}
}
使用示例:
int main() {
// 创建包含4个线程的线程池
ThreadPool pool(4);
// 提交一些任务
for (int i = 0; i < 8; ++i) {
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));
std::cout << "Task " << i << " completed" << std::endl;
});
}
// 主线程可以继续执行其他操作
// 线程池在析构时会自动关闭并清理资源
return 0;
}
上述代码实现了一个基础的线程池,它具有以下特点:
- 能够创建指定数量的工作线程。
- 采用线程安全的任务队列来存储待执行的任务。
- 借助条件变量实现任务的等待和通知机制。
- 支持线程池的优雅关闭。
- 可以安全地提交可调用对象作为任务。
在实际应用中,你可以根据具体需求对线程池进行扩展,例如添加任务优先级、实现任务执行结果的获取、动态调整线程数量等功能。