【C++实战】打造高性能线程池,轻松实现并发任务管理!(附代码)

文摘   2025-01-05 10:03   浙江  

线程池听起来高大上,其实就是一群勤劳的小蚂蚁,随时待命处理各种任务。今天咱就聊聊怎么用C++搭建一个简单又高效的线程池,让你的程序飞起来!


1

线程池是啥玩意儿?


线程池 说白了就是一堆预先创建好的线程,等着执行各种任务。想象一下你开了家快递公司,招了一群小哥随时待命送快递,这就是线程池的意思。


好处可多了:


  1. 省去了反复创建和销毁线程的麻烦,效率杠杠的。
  2. 能控制并发线程数,避免系统被 线程 撑爆。
  3. 任务排队更有序,优先级管理也方便。

2

怎么实现这玩意儿?


咱们一步步来:


  1. 搞个 任务队列 ,存放待处理的活儿。
  2. 整一帮 工作线程 ,没活就睡觉,有活就干活。
  3. 来个 添加任务 的方法,把新任务塞进队列。
  4. 整个 停止 的机制,让线程池优雅退出。

好,上代码:


#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;

};

3

代码解释


这段代码看着挺唬人,其实逻辑很简单:


  1. 构造函数
     里创建了一群工作线程,它们都在跑一个无限循环。
  2. 循环里,线程先 等待任务 。没任务就睡觉,有任务就醒来干活。
  3. enqueue
     方法用来添加新任务。它把任务扔进队列,然后吵醒一个睡觉的线程。
  4. 析构函数
     负责收尾工作,让所有线程体面地退出。

温馨提示:这里用了不少C++11的新特性,比如 lambda表达式 、 右值引用 啥的。不熟悉的小伙伴可以去补补课。


4

实战演练


来,咱们用这个线程池干点啥:


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秒钟。


5

注意事项


  1. 线程池大小要根据你的 CPU核心数 和任务特点来定。太少发挥不出并发的威力,太多反而会因为 上下文切换 拖累性能。


  2. 如果任务之间有依赖关系,小心别 死锁 了。


  3. 对于 IO密集型 的任务,线程池可能不是最佳选择。你可能需要考虑 异步IO 或 协程 。


  4. 这个简单的线程池没有 优先级 管理。如果需要,你得自己加点料。


  5. 在 多核CPU 上,可以考虑用std::hardware_concurrency()来获取理想的线程数。


好了,今天的线程池小课堂到此结束。去试试吧,让你的程序多线程飞起来!记住, 并发编程 是把双刃剑,用好了事半功倍,用不好就是灾难。慢慢来,多练习,你会发现一个神奇的并发世界!



椰子树的秘密
优质内容创作者
 最新文章