线程池听起来高大上,其实就是一群勤劳的小蚂蚁,随时待命处理各种任务。今天咱就聊聊怎么用C++搭建一个简单又高效的线程池,让你的程序飞起来!
线程池 说白了就是一堆预先创建好的线程,等着执行各种任务。想象一下你开了家快递公司,招了一群小哥随时待命送快递,这就是线程池的意思。
好处可多了:
咱们一步步来:
好,上代码:
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
class ThreadPool {
public:
ThreadPool(size_t numThreads) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queueMutex);
condition.wait(lock, [this] { return stop || !tasks.empty(); });
if (stop && tasks.empty()) return;
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
template<class F>
void enqueue(F&& f) {
{
std::unique_lock<std::mutex> lock(queueMutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers) {
worker.join();
}
}
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queueMutex;
std::condition_variable condition;
bool stop = false;
};
这段代码看着挺唬人,其实逻辑很简单:
- 构造函数
- 循环里,线程先 等待任务 。没任务就睡觉,有任务就醒来干活。
- enqueue 方法用来添加新任务。它把任务扔进队列,然后吵醒一个睡觉的线程。
- 析构函数
温馨提示:这里用了不少C++11的新特性,比如 lambda表达式 、 右值引用 啥的。不熟悉的小伙伴可以去补补课。
来,咱们用这个线程池干点啥:
int main() {
ThreadPool pool(4); // 创建一个有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 << “ is done” << std::endl;
});
}
// 主线程等待一会儿,让任务有时间执行
std::this_thread::sleep_for(std::chrono::seconds(10));
return 0;
}
运行这段代码,你会看到8个任务被4个线程轮流处理。每个任务会打印自己的编号和执行它的线程ID,然后装模作样地“工作”1秒钟。
线程池大小要根据你的 CPU核心数 和任务特点来定。太少发挥不出并发的威力,太多反而会因为 上下文切换 拖累性能。
如果任务之间有依赖关系,小心别 死锁 了。
对于 IO密集型 的任务,线程池可能不是最佳选择。你可能需要考虑 异步IO 或 协程 。
这个简单的线程池没有 优先级 管理。如果需要,你得自己加点料。
在 多核CPU 上,可以考虑用std::hardware_concurrency()来获取理想的线程数。
好了,今天的线程池小课堂到此结束。去试试吧,让你的程序多线程飞起来!记住, 并发编程 是把双刃剑,用好了事半功倍,用不好就是灾难。慢慢来,多练习,你会发现一个神奇的并发世界!