线程池(大概)锁定条件变量和互斥量的问题
Thread pool (presumably) locking issue with condition variable and mutex
我正在研究线程池,运行 遇到了一个关于条件变量和互斥体的奇怪问题。我怀疑可能存在锁定问题,因为它有时有效,有时无效。这是代码的相关部分(删除了不相关的位):
class ThreadPool {
private:
std::atomic<bool> running;
std::atomic<size_t> unfinished_tasks;
std::queue<std::function<void(void)>> task_queue;
std::condition_variable cv_work;
std::mutex mtx_queue;
std::vector<std::thread> threads;
public:
ThreadPool(size_t num_threads = std::thread::hardware_concurrency());
~ThreadPool();
template<class T, class Fn>
std::future<T> queueTask(Fn&& fn);
};
ThreadPool::ThreadPool(size_t num_threads) :
running(true), unfinished_tasks(0) {
auto thread_loop = [&] {
while (running.load()) {
std::unique_lock<std::mutex> lock(mtx_queue);
if (!task_queue.empty()) {
auto work = task_queue.front();
task_queue.pop();
lock.unlock();
work();
unfinished_tasks--;
} else {
std::cout << std::this_thread::get_id() << " going to sleep..." << std::endl;
cv_work.wait(lock);
}
}};
threads.reserve(num_threads);
for (size_t i = 0; i < num_threads; i++) {
threads.push_back(std::thread(thread_loop));
}
}
template<class T, class Fn>
inline std::future<T> ThreadPool::queueTask(Fn&& fn) {
// func = lambda containing packaged task with fn
mtx_queue.lock();
task_queue.push(func);
mtx_queue.unlock();
unfinished_tasks++;
cv_work.notify_one();
return future;
}
一旦我注释掉包含调试输出的行,向线程池添加大量小任务将使它在某个时刻锁定,在调试输出到位的情况下,它将正确完成所有任务。我不太确定问题出在哪里。
您有竞争条件。 queueTask
可以在你的线程函数等待之前通知 cv_work
。在调用 cv_work.notify_one()
之前不要解锁 mtx_queue
。
我正在研究线程池,运行 遇到了一个关于条件变量和互斥体的奇怪问题。我怀疑可能存在锁定问题,因为它有时有效,有时无效。这是代码的相关部分(删除了不相关的位):
class ThreadPool {
private:
std::atomic<bool> running;
std::atomic<size_t> unfinished_tasks;
std::queue<std::function<void(void)>> task_queue;
std::condition_variable cv_work;
std::mutex mtx_queue;
std::vector<std::thread> threads;
public:
ThreadPool(size_t num_threads = std::thread::hardware_concurrency());
~ThreadPool();
template<class T, class Fn>
std::future<T> queueTask(Fn&& fn);
};
ThreadPool::ThreadPool(size_t num_threads) :
running(true), unfinished_tasks(0) {
auto thread_loop = [&] {
while (running.load()) {
std::unique_lock<std::mutex> lock(mtx_queue);
if (!task_queue.empty()) {
auto work = task_queue.front();
task_queue.pop();
lock.unlock();
work();
unfinished_tasks--;
} else {
std::cout << std::this_thread::get_id() << " going to sleep..." << std::endl;
cv_work.wait(lock);
}
}};
threads.reserve(num_threads);
for (size_t i = 0; i < num_threads; i++) {
threads.push_back(std::thread(thread_loop));
}
}
template<class T, class Fn>
inline std::future<T> ThreadPool::queueTask(Fn&& fn) {
// func = lambda containing packaged task with fn
mtx_queue.lock();
task_queue.push(func);
mtx_queue.unlock();
unfinished_tasks++;
cv_work.notify_one();
return future;
}
一旦我注释掉包含调试输出的行,向线程池添加大量小任务将使它在某个时刻锁定,在调试输出到位的情况下,它将正确完成所有任务。我不太确定问题出在哪里。
您有竞争条件。 queueTask
可以在你的线程函数等待之前通知 cv_work
。在调用 cv_work.notify_one()
之前不要解锁 mtx_queue
。