C++ Condition Variable调用notify后主线程无法唤醒问题
主线程等待条件变量无法被工作线程唤醒的问题解决
问题描述
我编写了一段多线程代码,主线程等待条件变量,工作线程负责通知它。代码示例如下:
#include <thread> #include <condition_variable> #include <mutex> #include <iostream> std::mutex mt; std::condition_variable cv; bool flag = false; void worker() { std::unique_lock lock(mt); std::cout << "Worker started.\n"; flag = true; lock.release(); cv.notify_one(); std::cout << "Worker done.\n"; } int main() { std::thread thread(worker); std::unique_lock lock(mt); std::cout << "Main waiting.\n"; cv.wait(lock, [](){ std::cout << "Main checking: " << flag << '\n'; return flag; }); std::cout << "Main done.\n"; thread.join(); }
原本预期会出现以下两种情况之一:
- 主线程先获取锁,等待工作线程完成;
- 工作线程先获取锁,完成后主线程无需等待。
但实际运行时主线程始终无法唤醒,输出内容如下:
Main waiting.
Main checking: 0
Worker started.
Worker done.
程序最终陷入挂起状态,请问该如何解决此问题?
问题根源
问题出在工作线程中的lock.release()调用——std::unique_lock::release()的作用是返回指向互斥量的指针,并释放unique_lock对该互斥量的所有权,但不会改变互斥量的锁定状态。
你的代码中,unique_lock是在持有锁的情况下调用release的,这导致互斥量一直处于锁定状态。当工作线程调用cv.notify_one()后,主线程被唤醒,但它需要重新获取互斥量才能继续执行(条件变量的wait唤醒后会自动尝试加锁),而此时互斥量仍然是锁定状态,主线程因此阻塞在获取锁的步骤,表现为程序挂起。
解决方法
方法一:使用unlock()替代release()
直接调用lock.unlock()手动解锁互斥量,这样主线程唤醒后可以正常获取锁:
void worker() { std::unique_lock lock(mt); std::cout << "Worker started.\n"; flag = true; lock.unlock(); // 手动解锁互斥量 cv.notify_one(); std::cout << "Worker done.\n"; }
方法二:利用unique_lock的作用域自动解锁
将unique_lock放在局部作用域中,当作用域结束时,unique_lock会自动解锁互斥量,无需手动调用:
void worker() { { std::unique_lock lock(mt); std::cout << "Worker started.\n"; flag = true; } // lock离开作用域,自动解锁互斥量 cv.notify_one(); std::cout << "Worker done.\n"; }
方法三:若必须使用release(),需先手动解锁
如果一定要保留release()调用,必须先调用unlock()释放互斥量,再调用release()放弃所有权:
void worker() { std::unique_lock lock(mt); std::cout << "Worker started.\n"; flag = true; lock.unlock(); // 先解锁互斥量 lock.release(); // 再释放unique_lock对互斥量的所有权 cv.notify_one(); std::cout << "Worker done.\n"; }
内容的提问来源于stack exchange,提问作者Weak to Enuma Elish
相关产品推荐
相关产品推荐

