使用std::condition_variable退出程序时触发互斥锁错误的问题求解
使用std::condition_variable退出程序时触发互斥锁错误的问题求解
老哥,你的问题根源出在错误地在多个线程间共享同一个std::unique_lock对象上,这可是C++多线程里的常见坑!咱们一步步拆解问题和解决方案:
为什么会触发「unlock of unowned mutex」错误?
std::unique_lock是线程专属的锁管理对象,它的所有权绑定到创建它的线程(也就是你的主线程)。你把myLock按引用传给子线程后,子线程拿着不属于自己的锁对象操作,会导致锁的状态彻底混乱:
- 主线程结束时会自动销毁
myLock,此时它可能还持有锁,或者子线程还在通过引用操作这个已经失效的锁 - 子线程里调用
myCV.wait(myLock)时,实际是在操作主线程的锁实例,当锁最终被析构时,就会触发“解锁未拥有的互斥锁”的断言错误
正确的实现方式
核心原则是:每个线程要使用自己的std::unique_lock实例,不要跨线程共享锁对象。同时,多线程访问的isRunning变量需要保证线程安全,建议用std::atomic<bool>或者被互斥锁保护。
下面是修正后的完整代码:
#include <mutex> #include <condition_variable> #include <thread> #include <iostream> #include <atomic> int main() { std::condition_variable myCV; std::mutex myMutex; std::atomic<bool> isRunning{ true }; // 用原子变量保证线程安全 // 子线程不再捕获主线程的lock,而是自己创建锁 std::jthread myThread([&isRunning, &myCV, &myMutex]() { while (isRunning) { std::unique_lock<std::mutex> myLock(myMutex); myCV.wait(myLock); // 用当前线程自己的锁等待 if (!isRunning) break; // 防止虚假唤醒后继续执行 // do some work here std::cout << "Thread processed data" << std::endl; } std::cout << "Exited from myThread while loop." << std::endl; }); for (int i = 0; i < 100; i++) { { std::lock_guard<std::mutex> lock(myMutex); // 如果需要传递数据给子线程,也应该在这里更新(受锁保护) } myCV.notify_one(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::cout << "Test loop " << i << std::endl; } // 退出流程:先标记停止,再通知,确保子线程能正确退出 isRunning = false; myCV.notify_one(); // std::jthread会自动join,这里可以不用手动调用,不过如果是普通thread需要join() return 0; }
关键修正点说明
- 移除跨线程的unique_lock共享:子线程内部创建自己的
std::unique_lock,确保锁的所有权属于当前线程,避免状态混乱 - 线程安全的控制变量:用
std::atomic<bool>管理isRunning,避免多线程读写时的数据竞争;如果不用原子变量,也可以在读写isRunning时加互斥锁保护 - 处理虚假唤醒:在wait之后额外检查
isRunning,因为条件变量可能被虚假唤醒,确保此时确实需要退出循环 - 规范的退出流程:先设置
isRunning为false,再调用notify_one(),让子线程在wait醒来后能检测到退出信号
这样修改后,程序就能优雅退出,不会再触发互斥锁相关的断言错误了。
备注:内容来源于stack exchange,提问作者Jepessen
相关产品推荐
相关产品推荐

