diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..5f7109c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++.exe 生成活动文件", + "command": "D:\\mingw64\\bin\\g++.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "调试器生成的任务。" + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/ThreadPool.h b/ThreadPool.h index 4183203..a8aa91b 100644 --- a/ThreadPool.h +++ b/ThreadPool.h @@ -31,31 +31,34 @@ class ThreadPool { }; // the constructor just launches some amount of workers -inline ThreadPool::ThreadPool(size_t threads) - : stop(false) -{ - for(size_t i = 0;i task; - { std::unique_lock lock(this->queue_mutex); - this->condition.wait(lock, - [this]{ return this->stop || !this->tasks.empty(); }); - if(this->stop && this->tasks.empty()) + // 关键修复:等待条件同时检查 stop 和任务队列 + this->condition.wait(lock, [this] { + return this->stop || !this->tasks.empty(); + }); + + // 若 stop 且任务队列为空,退出线程 + if (this->stop && this->tasks.empty()) { return; + } + + // 否则执行任务 task = std::move(this->tasks.front()); this->tasks.pop(); } - - task(); + task(); // 执行任务时不持有锁 } } ); + } } // add new work item to the pool @@ -84,15 +87,20 @@ auto ThreadPool::enqueue(F&& f, Args&&... args) } // the destructor joins all threads -inline ThreadPool::~ThreadPool() -{ +inline ThreadPool::// 修改后的析构函数 +~ThreadPool() { { std::unique_lock lock(queue_mutex); - stop = true; + stop = true; // 设置停止标志 + } + condition.notify_all(); // 唤醒所有等待的线程 + + // 等待所有线程结束(添加 joinable 检查) + for (std::thread& worker : workers) { + if (worker.joinable()) { // 避免重复 join 导致的错误 + worker.join(); + } } - condition.notify_all(); - for(std::thread &worker: workers) - worker.join(); } #endif diff --git a/test_deadlock.cpp b/test_deadlock.cpp new file mode 100644 index 0000000..caca56d --- /dev/null +++ b/test_deadlock.cpp @@ -0,0 +1,47 @@ +#include "ThreadPool.h" +#include +#include +#include +#include + +int main() { + // 测试场景1:正常析构(无任务) + { + ThreadPool pool(4); + // 立即析构,无任务执行 + } + std::cout << "Test 1 passed: No deadlock when destroying empty pool." << std::endl; + + // 测试场景2:提交任务后析构 + { + ThreadPool pool(4); + std::atomic counter(0); + + // 提交大量短任务 + for (int i = 0; i < 1000; ++i) { + pool.enqueue([&counter] { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + counter.fetch_add(1, std::memory_order_relaxed); + }); + } + + // 不等待任务完成,直接析构 + } + std::cout << "Test 2 passed: No deadlock when destroying pool with pending tasks." << std::endl; + + // 测试场景3:提交耗时任务后析构 + { + ThreadPool pool(4); + + // 提交一个长时间运行的任务 + pool.enqueue([] { + std::this_thread::sleep_for(std::chrono::seconds(2)); + }); + + // 立即析构(任务可能仍在执行) + } + std::cout << "Test 3 passed: No deadlock when destroying pool with running tasks." << std::endl; + + std::cout << "All tests passed!" << std::endl; + return 0; +} \ No newline at end of file diff --git a/test_deadlock.exe b/test_deadlock.exe new file mode 100644 index 0000000..d6f46d1 Binary files /dev/null and b/test_deadlock.exe differ