主线程等待子线程循环迭代完成?代码死锁问题排查
问题描述
我编写了两段C++多线程代码:
- 第一段中,主线程通过
std::condition_variable通知子线程执行循环,但主线程不会等待所有子线程完成当前迭代就继续执行; - 第二段尝试新增
std::condition_variable和std::atomic计数器来实现等待逻辑,却导致程序完全死锁,仅能打印线程创建前的提示信息。
请问哪里出错了?该如何修正?
第一段代码
#include <mutex> #include <condition_variable> #include <thread> #include <iostream> #include <vector> #include <syncstream> int main() { std::condition_variable myCV; std::mutex myMutex; bool isRunning{ true }; const size_t numberOfThreads{ 6 }; std::vector<std::jthread> threads; for (size_t i = 0; i < numberOfThreads; i++) { threads.emplace_back( [&isRunning, &myMutex, &myCV, i]() { std::unique_lock loopLock(myMutex); while (isRunning) { myCV.wait(loopLock); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } std::osyncstream oss{ std::cout }; oss << "Ended thread " << i << std::endl; } ); } for (int i = 0; i < 100; i++) { myCV.notify_all(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::cout << "Test loop " << i << std::endl; } isRunning = false; myCV.notify_all(); return 0; }
第二段代码
#include <mutex> #include <condition_variable> #include <thread> #include <iostream> #include <vector> #include <syncstream> #include <atomic> int main() { std::condition_variable myCV; std::mutex myMutex; bool isRunning{ true }; std::condition_variable loopEndCV; std::atomic<size_t> threadCounter{ 0 }; std::mutex loopEndMutex; const size_t numberOfThreads{ 6 }; std::vector<std::jthread> threads; std::cout << "Instantiating threads..." << std::endl; for (size_t i = 0; i < numberOfThreads; i++) { threads.emplace_back( [&, i]() { std::unique_lock loopLock(myMutex); while (isRunning) { myCV.wait(loopLock); std::this_thread::sleep_for(std::chrono::milliseconds(500)); --threadCounter; if (threadCounter.load() == 0) { loopEndCV.notify_one(); } } std::osyncstream oss{ std::cout }; oss << "Ended thread " << i << std::endl; } ); } for (int i = 0; i < 100; i++) { threadCounter = numberOfThreads; myCV.notify_all(); std::unique_lock loopEndLock(loopEndMutex); loopEndCV.wait(loopEndLock, [&threadCounter]() { return threadCounter.load() == 0; }); std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::cout << "Test loop " << i << std::endl; } isRunning = false; myCV.notify_all(); return 0; }
问题分析与修正方案
第一段代码的问题
主线程每次调用notify_all()后仅休眠20ms就进入下一轮循环,完全没有等待子线程完成当前迭代。子线程被唤醒后执行sleep_for(500ms)的过程中,主线程已经再次触发通知,导致子线程的迭代逻辑被频繁干扰,主线程与子线程的执行节奏完全脱节。
第二段代码死锁的原因
- 锁长时间被持有:子线程的
std::unique_lock loopLock(myMutex)在整个while(isRunning)循环内持续持有锁,仅在wait()时临时释放。子线程被唤醒后执行sleep_for(500ms)期间仍持有锁,导致其他子线程无法获取锁完成唤醒后的逻辑,最终只有一个子线程能执行任务。 - 计数器逻辑失效:主线程设置
threadCounter = numberOfThreads并通知后,由于多数子线程被锁阻塞,threadCounter永远无法减到0,主线程卡在loopEndCV.wait()中,形成死锁。
修正后的代码
#include <mutex> #include <condition_variable> #include <thread> #include <iostream> #include <vector> #include <syncstream> #include <atomic> int main() { std::condition_variable myCV; std::mutex myMutex; bool isRunning{ true }; int currentIteration{ 0 }; // 用于避免虚假唤醒的迭代标记 std::condition_variable loopEndCV; std::atomic<size_t> threadCounter{ 0 }; std::mutex loopEndMutex; const size_t numberOfThreads{ 6 }; std::vector<std::jthread> threads; std::cout << "Instantiating threads..." << std::endl; for (size_t i = 0; i < numberOfThreads; i++) { threads.emplace_back( [&, i]() { while (isRunning) { std::unique_lock loopLock(myMutex); // 等待主线程发起新迭代,同时处理虚假唤醒 myCV.wait(loopLock, [&]() { return !isRunning || currentIteration > 0; }); if (!isRunning) break; // 释放锁,让其他子线程能被唤醒执行 loopLock.unlock(); // 执行任务 std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::osyncstream oss{ std::cout }; oss << "Thread " << i << " finished iteration " << currentIteration << std::endl; // 最后一个子线程完成时通知主线程 if (--threadCounter == 0) { std::unique_lock endLock(loopEndMutex); loopEndCV.notify_one(); } } std::osyncstream oss{ std::cout }; oss << "Ended thread " << i << std::endl; } ); } for (int i = 1; i <= 100; i++) { { std::lock_guard lock(myMutex); currentIteration = i; threadCounter = numberOfThreads; } myCV.notify_all(); std::unique_lock loopEndLock(loopEndMutex); // 等待所有子线程完成当前迭代 loopEndCV.wait(loopEndLock, [&]() { return threadCounter == 0; }); std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::cout << "Test loop " << i-1 << " completed" << std::endl; } { std::lock_guard lock(myMutex); isRunning = false; currentIteration = 0; } myCV.notify_all(); return 0; }
关键修复说明
- 及时释放锁:子线程被唤醒后立即释放
myMutex,让所有子线程都能获取锁并执行任务,避免单线程独占锁。 - 迭代标记防虚假唤醒:新增
currentIteration变量,确保子线程仅在主线程明确发起新迭代时才执行任务,避免条件变量的虚假唤醒干扰逻辑。 - 安全的计数器通知:利用原子变量
threadCounter确保多线程计数更新安全,仅当最后一个子线程完成时才通知主线程。 - 状态更新加锁:修改
currentIteration和isRunning时持有myMutex,保证子线程看到的状态一致。
内容的提问来源于stack exchange,提问作者Jepessen
相关产品推荐
相关产品推荐

