C++条件变量满足条件却无限等待的问题排查与修复
条件变量等待线程无限阻塞的修复
原代码
#include <thread> #include <mutex> #include <condition_variable> #include <iostream> using namespace std; std::mutex mtx; std::condition_variable cv; int main() { int balance = 0; std::thread withdraw([&](int amt){ std::unique_lock<std::mutex> ul(mtx); cv.wait(ul, [balance, amt]{ return balance >= amt; }); balance -= amt; std::cout << "Amount deducted: " << amt << ", current balance: " << balance << endl; }, 500); std::thread deposit([&](int amt){ std::lock_guard<mutex> lg(mtx); balance += amt; std::cout << "Amount added: " << amt << ", current balance: " << balance << endl; cv.notify_one(); }, 1000); withdraw.join(); deposit.join(); return 0; }
问题现象
运行时仅输出存款信息,取款线程无限阻塞:
➜ synchronization git:(master) ✗ ./a.out Amount added: 1000, current balance: 1000
问题根源
你在cv.wait的判断Lambda中用值捕获了balance,这意味着Lambda内部保存的是balance的初始值(0)。即使deposit线程修改了主函数中的balance,Lambda里的balance始终是最初的0,导致balance >= amt的条件永远不成立,取款线程无法被唤醒继续执行。
修复方案
将balance改为引用捕获,让Lambda能访问到balance的最新值,有两种写法:
写法1:显式引用捕获balance
修改等待条件的Lambda:
cv.wait(ul, [&balance, amt]{ return balance >= amt; });
写法2:捕获外部作用域的所有引用
因为外层的withdraw线程Lambda已经用[&]捕获了所有外部变量的引用,内部Lambda可以直接继承这个捕获规则:
cv.wait(ul, [&]{ return balance >= amt; });
修复后的完整代码
#include <thread> #include <mutex> #include <condition_variable> #include <iostream> using namespace std; std::mutex mtx; std::condition_variable cv; int main() { int balance = 0; std::thread withdraw([&](int amt){ std::unique_lock<std::mutex> ul(mtx); cv.wait(ul, [&balance, amt]{ return balance >= amt; }); // 修改捕获方式 balance -= amt; std::cout << "Amount deducted: " << amt << ", current balance: " << balance << endl; }, 500); std::thread deposit([&](int amt){ std::lock_guard<mutex> lg(mtx); balance += amt; std::cout << "Amount added: " << amt << ", current balance: " << balance << endl; cv.notify_one(); }, 1000); withdraw.join(); deposit.join(); return 0; }
预期运行结果
Amount added: 1000, current balance: 1000 Amount deducted: 500, current balance: 500
内容的提问来源于stack exchange,提问作者itnovice
相关产品推荐
相关产品推荐

