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

C++11如何实现任意子线程结束后立即唤醒阻塞的主线程

问题原因

你代码的问题出在反复给同一个std::shared_future变量赋值:每次给ret赋新值时,前一个shared_future对象的引用计数会降到0触发析构。而std::future/std::shared_future的析构逻辑规定:如果其绑定的异步任务还未执行完成,析构函数会阻塞等待任务结束才会继续执行后续逻辑。

你的三次赋值顺序是先绑定90秒的任务、再绑定20秒的任务、最后绑定2秒的任务:

  • 第二次赋值时,需要先释放持有的90秒任务的future,此时90秒任务还在运行,程序会阻塞等待90秒任务跑完才完成第二次赋值
  • 第三次赋值时,需要释放持有的20秒任务的future,同样阻塞等待20秒任务跑完才完成第三次赋值
  • 最后调用ret.get()时等待2秒任务跑完
    总耗时等于三个任务耗时之和,最终输出2 1,和你观察到的现象完全一致。
正确实现方案

C11标准库没有直接提供等待任意future就绪的接口,你可以使用以下兼容C11的方案实现需求:

实现思路

用条件变量+共享标记实现,每个子线程执行完成后主动修改共享标记、触发条件变量通知,主线程只需要等待条件变量的通知即可拿到第一个完成的任务结果。

代码示例

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>

std::pair<size_t, size_t> fun(size_t i, size_t j)
{
    std::this_thread::sleep_for(std::chrono::seconds(i * j));
    return { i, j };
}

int main()
{
    std::mutex mtx;
    std::condition_variable cv;
    std::pair<size_t, size_t> result;
    bool result_ready = false;

    // 批量创建子线程
    std::vector<std::thread> threads;
    threads.emplace_back([&](){
        auto res = fun(10,9);
        std::lock_guard<std::mutex> lock(mtx);
        if(!result_ready) { // 只保留第一个完成的任务结果
            result = res;
            result_ready = true;
            cv.notify_one();
        }
    });
    threads.emplace_back([&](){
        auto res = fun(5,4);
        std::lock_guard<std::mutex> lock(mtx);
        if(!result_ready) {
            result = res;
            result_ready = true;
            cv.notify_one();
        }
    });
    threads.emplace_back([&](){
        auto res = fun(2,1);
        std::lock_guard<std::mutex> lock(mtx);
        if(!result_ready) {
            result = res;
            result_ready = true;
            cv.notify_one();
        }
    });

    // 主线程阻塞等待第一个结果返回
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [&](){ return result_ready; });

    // 输出结果
    std::cout << result.first << "\t" << result.second << "\n";

    // 按需选择:不需要等待剩余线程完成就调用detach,需要等待就调用join
    for(auto& t : threads) {
        t.detach();
    }

    return 0;
}

该代码运行后仅需等待2秒就会输出2 1,符合预期需求。如果可以使用C++20标准,也可以直接调用标准库提供的std::when_any接口实现相同逻辑,代码会更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:15:08