线程池中,对全局变量 Map 赋值,造成程序不稳定

博客讨论了在线程池中使用全局变量导致的程序运行不稳定的問題。由于多线程环境中未对全局变量进行同步控制,导致程序一会成功,一会失败。提出了两种解决方案:一是将赋值操作移出异步线程,二是复制全局变量为局部变量在池中使用。同时强调非主线程访问主线程变量需确保其为final或初始化。

现象:

        线程池中使用了全局变量 map,并在异步线程程序中对 map进行了赋值,造成程序运行出现一会儿成功,一会儿失败,运行不稳定;

原因:

        线程池中多全局变量没有做线程控制;

修改:

        方式一:比较笨,将赋值工作在异步线程外进行;

        方式二: 略笨,copy 全局变量为 局部变量,放入线程池中使用

关键字: 异步线程池,多线程

注:非主线程调用主线程的变量时,该 变量必须是final的,或者 初始化写死的。

<think> 我们之前讨论了单例模式,现在用户要求使用多例模式(Multiton)来定义线程池类ThreadPool。多例模式是单例模式的扩展,它确保一个类有有限个实例(通常通过键值映射),并提供全局访问点。 ### 多例模式线程池设计思路 1. **多例模式核心**:管理多个线程池实例,每个实例通过唯一名称标识。 2. **线程池功能**:固定大小的线程池,包含任务队列和一组工作线程。 3. **线程安全**:使用互斥锁保护任务队列。 ### 实现步骤 1. 定义线程池类 `ThreadPool`,采用多例模式。 2. 每个线程池实例有固定数量的工作线程。 3. 工作线程循环从任务队列中取出任务执行。 4. 提供提交任务的接口 `submit`。 5. 提供关闭线程池的方法 `shutdown`。 ### 代码实现 ```cpp #include <iostream> #include <vector> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <functional> #include <stdexcept> #include <map> #include <unordered_map> #include <memory> #include <atomic> class ThreadPool { public: // 获取指定名称的线程池实例(多例模式) static ThreadPool& getInstance(const std::string& name, size_t threadCount = std::thread::hardware_concurrency()) { // 双检锁确保线程安全 if (instances_.find(name) == instances_.end()) { std::lock_guard<std::mutex> lock(mutex_); if (instances_.find(name) == instances_.end()) { instances_[name] = std::shared_ptr<ThreadPool>(new ThreadPool(threadCount)); } } return *instances_[name]; } // 提交任务到线程池 template<class F, class... Args> auto submit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> { using return_type = decltype(f(args...)); // 将任务封装到packaged_task中,以便获取future auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex_); // 不允许在停止后提交任务 if (stop_) throw std::runtime_error("submit on stopped ThreadPool"); tasks_.emplace([task]() { (*task)(); }); } condition_.notify_one(); return res; } // 关闭线程池(等待所有任务完成) void shutdown() { { std::unique_lock<std::mutex> lock(queue_mutex_); stop_ = true; } condition_.notify_all(); for (std::thread& worker : workers_) { if (worker.joinable()) worker.join(); } } // 禁止拷贝和赋值 ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; private: // 私有构造函数 explicit ThreadPool(size_t threadCount) : stop_(false) { for (size_t i = 0; i < threadCount; ++i) { workers_.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queue_mutex_); 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() { if (!stop_) { shutdown(); } } private: // 静态成员:管理多例实例 static std::unordered_map<std::string, std::shared_ptr<ThreadPool>> instances_; static std::mutex mutex_; // 保护instances_ // 线程池成员 std::vector<std::thread> workers_; std::queue<std::function<void()>> tasks_; std::mutex queue_mutex_; std::condition_variable condition_; std::atomic_bool stop_; }; // 初始化静态成员 std::unordered_map<std::string, std::shared_ptr<ThreadPool>> ThreadPool::instances_; std::mutex ThreadPool::mutex_; // =============== 测试程序 =============== void testTask(int id) { std::cout << "Task " << id << " started by thread " << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Task " << id << " ended" << std::endl; } int main() { // 获取两个不同的线程池实例 ThreadPool& poolA = ThreadPool::getInstance("A", 2); // 2个线程 ThreadPool& poolB = ThreadPool::getInstance("B", 4); // 4个线程 // 提交任务到poolA std::cout << "Submitting tasks to pool A:" << std::endl; for (int i = 0; i < 5; ++i) { poolA.submit(testTask, i); } // 提交任务到poolB std::cout << "Submitting tasks to pool B:" << std::endl; for (int i = 10; i < 15; ++i) { poolB.submit(testTask, i); } // 等待一段时间让任务执行 std::this_thread::sleep_for(std::chrono::seconds(5)); // 关闭线程池(在程序结束前) poolA.shutdown(); poolB.shutdown(); return 0; } ``` ### 关键设计说明 1. **多例模式实现**: - 使用静态映射 `instances_` 存储不同名称的线程池实例 - 双检锁确保实例创建的线程安全 2. **线程池核心**: - **任务队列**:使用 `std::queue` 存储待执行任务(类型为 `std::function<void()>`) - **工作线程**:在构造时创建指定数量的线程,每个线程循环从队列取任务 - **条件变量**:用于线程间同步,当任务到来时唤醒等待线程 3. **任务提交**: - 使用 `submit` 方法提交任务,返回 `std::future` 以便获取结果 - 支持任意可调用对象和参数(通过 `std::bind` 和可变模板参数) 4. **资源管理**: - 析构函数自动关闭线程池 - 使用 `shutdown` 方法显式关闭(等待任务完成) ### 测试程序说明 1. 创建两个线程池实例(名称分别为"A"和"B") 2. 向poolA提交5个任务(由2个线程执行) 3. 向poolB提交5个任务(由4个线程执行) 4. 主线程等待5秒后关闭线程池 ### 预期输出 ``` Submitting tasks to pool A: Submitting tasks to pool B: Task 0 started by thread 140... (线程ID) Task 10 started by thread 140... Task 11 started by thread 140... ... (可以看到poolA最多同时2个任务,poolB最多同时4个任务) ``` ### 注意事项 1. 多例模式中每个实例都是独立配置的(如线程数量) 2. 任务提交是线程安全的 3. 使用 `shutdown` 确保线程池正确停止 §§相关问题§§ 1. 在多线程环境中,如何避免线程池任务队列成为性能瓶颈? 2. 线程池中任务执行异常应该如何处理? 3. 如何实现动态调整线程池大小的功能? 4. 多例模式与单例模式在资源管理上的主要区别是什么? </think> # 多例模式线程池实现与测试 下面我将使用多例模式(Multiton pattern)实现一个线程池类`ThreadPool`,并提供完整的测试程序。 ## 多例模式线程池实现 ```cpp #include <iostream> #include <vector> #include <queue> #include <thread> #include <mutex> #include <condition_variable> #include <functional> #include <stdexcept> #include <map> #include <memory> #include <atomic> // 线程池类(多例模式) class ThreadPool { public: // 禁用拷贝构造和赋值 ThreadPool(const ThreadPool&) = delete; ThreadPool& operator=(const ThreadPool&) = delete; // 获取指定名称的线程池实例 static ThreadPool& getInstance(const std::string& name, size_t threadCount = std::thread::hardware_concurrency()) { // 双检锁确保线程安全 if (instances_.find(name) == instances_.end()) { std::lock_guard<std::mutex> lock(mutex_); if (instances_.find(name) == instances_.end()) { instances_.emplace(name, std::unique_ptr<ThreadPool>(new ThreadPool(threadCount))); } } return *instances_[name]; } // 提交任务到线程池 template<class F, class... Args> auto submit(F&& f, Args&&... args) -> std::future<decltype(f(args...))> { using return_type = decltype(f(args...)); // 将任务封装到packaged_task中 auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...)); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queue_mutex_); // 不允许在停止后提交任务 if(stop_) throw std::runtime_error("submit on stopped ThreadPool"); // 将任务添加到队列 tasks_.emplace([task](){ (*task)(); }); } condition_.notify_one(); return res; } // 关闭线程池(等待所有任务完成) void shutdown() { { std::unique_lock<std::mutex> lock(queue_mutex_); stop_ = true; } condition_.notify_all(); for(std::thread &worker: workers_) { if(worker.joinable()) worker.join(); } } // 获取线程池名称 const std::string& getName() const { return name_; } // 获取线程池状态信息 void reportStatus() const { std::cout << "ThreadPool '" << name_ << "' status: "; std::cout << workers_.size() << " threads, "; std::cout << tasks_.size() << " pending tasks\n"; } // 析构函数 ~ThreadPool() { if(!stop_) { shutdown(); } } private: // 私有构造函数 explicit ThreadPool(size_t threadCount) : name_("unnamed"), stop_(false) { for(size_t i = 0; i < threadCount; ++i) { workers_.emplace_back([this] { while(true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queue_mutex_); 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(); } }); } } // 静态成员:管理多例实例 static std::map<std::string, std::unique_ptr<ThreadPool>> instances_; static std::mutex mutex_; // 实例成员 std::string name_; // 线程池名称 std::vector<std::thread> workers_; // 工作线程 std::queue<std::function<void()>> tasks_; // 任务队列 std::mutex queue_mutex_; // 任务队列互斥锁 std::condition_variable condition_; // 条件变量 std::atomic_bool stop_; // 停止标志 }; // 初始化静态成员 std::map<std::string, std::unique_ptr<ThreadPool>> ThreadPool::instances_; std::mutex ThreadPool::mutex_; // =============== 测试程序 =============== // 一个简单的任务函数 void taskFunction(int taskId) { std::cout << "Task " << taskId << " started by thread " << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 模拟工作 std::cout << "Task " << taskId << " completed" << std::endl; } // 计算平方的函数(返回计算结果) int computeSquare(int value) { std::cout << "Computing square of " << value << " on thread " << std::this_thread::get_id() << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(300)); // 模拟计算 return value * value; } int main() { // 获取不同名称的线程池实例 ThreadPool& cpuPool = ThreadPool::getInstance("CPU", 4); // 4个线程 ThreadPool& ioPool = ThreadPool::getInstance("IO", 2); // 2个线程 // 打印线程池状态 cpuPool.reportStatus(); ioPool.reportStatus(); // 提交任务到CPU池 std::cout << "\nSubmitting tasks to CPU pool:\n"; for (int i = 0; i < 8; ++i) { cpuPool.submit(taskFunction, i); } // 提交任务到IO池 std::cout << "\nSubmitting tasks to IO pool:\n"; for (int i = 10; i < 15; ++i) { ioPool.submit(taskFunction, i); } // 提交计算任务并获取结果 std::cout << "\nSubmitting computation tasks:\n"; std::vector<std::future<int>> results; for (int i = 1; i <= 5; ++i) { results.push_back(cpuPool.submit(computeSquare, i)); } // 等待所有任务完成 std::this_thread::sleep_for(std::chrono::seconds(2)); // 获取计算结果 std::cout << "\nComputation results:\n"; for (int i = 0; i < results.size(); ++i) { int result = results[i].get(); // 获取异步结果 std::cout << "Task " << (i+1) << " result: " << result << std::endl; } // 再次报告状态 std::cout << "\nFinal thread pool status:\n"; cpuPool.reportStatus(); ioPool.reportStatus(); // 程序结束时会自动调用shutdown return 0; } ``` ## 实现说明 1. **多例模式设计**: - 使用静态映射`instances_`存储不同名称的线程池实例 - `getInstance()`方法根据名称返回或创建线程池 - 双检锁(Double-Checked Locking)确保线程安全 2. **线程池核心功能**: - **任务队列**:使用`std::queue`存储待执行任务 - **工作线程**:在构造时创建一组工作线程 - **任务提交**:支持任意可调用对象和参数 - **结果获取**:使用`std::future`返回异步计算结果 - **线程同步**:使用互斥锁和条件变量管理任务队列 3. **生命周期管理**: - 析构函数自动关闭线程池 - 提供`shutdown()`方法显式关闭线程池 ## 测试程序说明 1. **创建线程池实例**: - CPU池:4个工作线程 - IO池:2个工作线程 2. **任务提交**: - 向CPU池提交8个简单任务 - 向IO池提交5个简单任务 - 向CPU池提交5个计算任务 3. **结果获取**: - 使用`std::future`获取计算任务的平方结果 4. **状态报告**: - 初始和最终状态报告显示线程池配置和待处理任务数 ## 预期输出 ``` ThreadPool 'CPU' status: 4 threads, 0 pending tasks ThreadPool 'IO' status: 2 threads, 0 pending tasks Submitting tasks to CPU pool: Submitting tasks to IO pool: Submitting computation tasks: Task 0 started by thread 139... Task 1 started by thread 140... Task 10 started by thread 142... Task 2 started by thread 141... Computing square of 1 on thread 139... Task 0 completed Task 3 started by thread 139... ... Task 14 completed Computation results: Task 1 result: 1 Task 2 result: 4 Task 3 result: 9 Task 4 result: 16 Task 5 result: 25 Final thread pool status: ThreadPool 'CPU' status: 4 threads, 0 pending tasks ThreadPool 'IO' status: 2 threads, 0 pending tasks ``` ## 多例模式与单例模式对比 | 特性 | 单例模式 | 多例模式 | |--------------|-----------------------------|-----------------------------| | 实例数量 | 1个 | 有限个(按名称区分) | | 适用场景 | 全局唯一资源管理 | 按类型/用途管理资源池 | | 线程池应用 | 整个应用共享一个线程池 | 不同任务类型使用不同线程池 | | 扩展性 | 固定 | 灵活,可按需创建新实例 | | 资源控制 | 集中管理 | 分散管理,可按需配置 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值