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

C++ Mutex与条件变量同步问题:主线程等待循环工作子线程执行完成

问题原因
  • 工作线程更新finished标记为true后没有触发条件变量通知,主线程的wait调用收不到唤醒信号,永久挂起。
  • 主线程持有互斥锁的状态下执行sleep,导致所有工作线程无法拿到锁进入下一轮等待,属于逻辑错误。
  • 循环变量重名:main函数中,外层循环变量i被内层重置finished数组的循环变量i覆盖,会导致外层循环执行次数异常。
  • 单一条件变量同时承载「工作线程等待任务」和「主线程等待完成」两类等待逻辑,容易出现信号互扰。
修复方案
  1. 新增独立条件变量cv_main专门用于主线程等待工作线程完成任务,避免信号冲突。
  2. 工作线程完成任务修改finished标记后,主动调用条件变量通知唤醒主线程。
  3. 缩小互斥锁的作用范围,主线程等待完成后立刻释放锁,再执行休眠逻辑。
  4. 修正循环变量重名问题,避免外层循环逻辑异常。
  5. 补充全量finished状态校验逻辑,确保主线程等待所有工作线程执行完成后再继续。
修正后完整代码
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <Windows.h>
#define N 3
std::mutex mtx;
std::condition_variable cv; // 用于工作线程等待任务触发
std::condition_variable cv_main; // 用于主线程等待任务全部完成
bool finished[N];

void print_id(int id) {
    while (1) {
        std::unique_lock<std::mutex> lck(mtx);
        // 等待任务触发:finished[id]为false时开始执行
        while (finished[id]) cv.wait(lck);
        // 任务逻辑
        std::cout << "thread " << id << '\n';
        // 标记当前线程任务完成
        finished[id] = true;
        // 通知主线程检查完成状态
        cv_main.notify_all();
    }
}

int main()
{
    std::thread threads[N];
    for (int i = 0; i < N; ++i) {
        threads[i] = std::thread(print_id, i);
        finished[i] = true; // 初始状态标记为已完成,等待触发
    }
    std::cout << N << " threads ready to race...\n";
    
    for (int i = 0; i < 5; i++) {
        // 把锁的作用域限制在任务触发+等待完成阶段
        {
            std::unique_lock<std::mutex> lck(mtx);
            // 重置所有线程完成标记,允许开始执行
            for (int j = 0; j < N; j++) {
                finished[j] = false;
            }
            // 通知所有工作线程开始执行
            cv.notify_all();
            // 等待所有工作线程完成本次任务
            cv_main.wait(lck, [] {
                for (int k = 0; k < N; k++) {
                    if (!finished[k]) return false;
                }
                return true;
            });
        }
        // 锁已经释放,工作线程可以进入下一轮等待,主线程休眠
        std::cout << "round " << i << " finished, Sleeping for 2s\n";
        Sleep(2000);
    }

    // 实际使用时需要补充退出逻辑通知工作线程结束,此处省略
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 06:39:02