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

C++中std::condition_variable正确使用及Worker类故障排查

问题原因分析

1. 任务被覆盖,无任务队列

你的Worker仅用单个std::function<void()> task存储任务,每次调用push都会覆盖之前的任务。比如循环push 10次时,只有最后一次的任务(打印9)会被保留,前面的任务全部被丢弃。

2. 未处理条件变量的虚假唤醒

new_task.wait(lock)未使用带谓词的版本,线程可能被虚假唤醒(并非因为调用notify_one),此时stop为false,就会重复执行当前的task,这也是单次push会无限打印"Hello"的核心原因。

3. 析构函数未正确终止线程

Worker的析构函数为空,当main函数结束时,Worker对象销毁,其内部的std::thread对象在析构时仍处于joinable状态,C++标准会直接调用std::terminate终止程序,这就是你看到terminate called without an active exception的原因。

4. 任务执行时持锁阻塞提交

线程执行task()时仍持有锁,导致后续push操作无法获取锁,任务提交被阻塞;同时执行完任务后没有正确重置流程,进一步加剧了重复执行的问题。

修正后的代码
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <atomic>
#include <iostream>
#include <queue>

class Worker {
public:
    Worker(Worker&&) = delete;
    Worker(const Worker&) = delete;
    Worker() 
        : stop(false)
        , thread(&Worker::worker_thread, this)
    {}

    void push(std::function<void()> _f) {
        std::unique_lock lock(thread_mutex);
        tasks.push(std::move(_f));
        new_task.notify_one();
    }

    ~Worker() {
        // 标记停止并唤醒线程
        {
            std::unique_lock lock(thread_mutex);
            stop = true;
        }
        new_task.notify_one();
        // 等待线程安全终止
        if (thread.joinable()) {
            thread.join();
        }
    }

private:
    void worker_thread() {
        std::unique_lock lock(thread_mutex);
        while (true) {
            // 仅在有任务或需要停止时唤醒
            new_task.wait(lock, [this]() {
                return stop || !tasks.empty();
            });

            if (stop && tasks.empty()) {
                // 停止且无剩余任务,退出线程
                return;
            }

            // 取出任务后释放锁,避免阻塞push
            auto task = std::move(tasks.front());
            tasks.pop();
            lock.unlock();

            // 执行任务
            task();

            // 重新获取锁,进入下一轮等待
            lock.lock();
        }
    }

    std::atomic<bool> stop;
    std::queue<std::function<void()>> tasks; // 任务队列存储多个任务
    std::thread thread;
    std::mutex thread_mutex;
    std::condition_variable new_task;
};

// 测试代码
int main() {
    Worker t;
    t.push([] { std::cout << "Hello from worker" << std::endl; });

    for (int i = 0; i < 10; ++i)
        t.push([i] { std::cout << i << std::endl; });

    return 0;
}
修正点说明
  • 任务队列:改用std::queue存储任务,确保所有提交的任务都能被依次执行,不会被覆盖。
  • 带谓词的wait:通过谓词确保线程仅在有任务或需要停止时被唤醒,彻底避免虚假唤醒导致的重复执行。
  • 安全终止线程:析构函数中先标记停止状态,唤醒线程后等待线程执行完剩余任务再join,避免程序异常终止。
  • 执行任务时解锁:取出任务后立即释放锁,让push操作可以随时提交任务,不会被任务执行过程阻塞。

内容的提问来源于stack exchange,提问作者ugo_capeto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 20:37:51