You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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;
}

关键修正点说明

  1. 移除跨线程的unique_lock共享:子线程内部创建自己的std::unique_lock,确保锁的所有权属于当前线程,避免状态混乱
  2. 线程安全的控制变量:用std::atomic<bool>管理isRunning,避免多线程读写时的数据竞争;如果不用原子变量,也可以在读写isRunning时加互斥锁保护
  3. 处理虚假唤醒:在wait之后额外检查isRunning,因为条件变量可能被虚假唤醒,确保此时确实需要退出循环
  4. 规范的退出流程:先设置isRunning为false,再调用notify_one(),让子线程在wait醒来后能检测到退出信号

这样修改后,程序就能优雅退出,不会再触发互斥锁相关的断言错误了。

备注:内容来源于stack exchange,提问作者Jepessen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 11:14:34