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

C++中如何同时等待多线程?是否存在非阻塞join实现thread_select?

C++ 实现类似 select() 的多线程等待方案

C++ 标准库没有直接提供类似 select() 的多线程等待接口,也不存在非阻塞版本的 join(),但可以通过以下两种方案实现类似 thread_select 的需求——让主线程等待任意一个子线程完成,而非固定等待某一个。

方案一:条件变量+状态标记(阻塞式,高效)

通过追踪线程完成状态,配合条件变量实现主线程的精准唤醒,避免无意义的CPU消耗。

实现逻辑

  1. 为每个子线程维护一个原子状态标记,记录其是否完成任务;
  2. 子线程完成任务后,更新自身状态并唤醒主线程;
  3. 主线程阻塞在条件变量上,直到有线程完成,随后遍历状态标记找到已完成的线程,调用 join() 回收资源。

示例代码

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

int main() {
    const int thread_count = 3;
    std::vector<std::thread> threads;
    std::vector<std::atomic<bool>> thread_completed(thread_count, false);
    std::mutex mtx;
    std::condition_variable cv;
    int completed_num = 0;

    // 创建子线程
    for (int i = 0; i < thread_count; ++i) {
        threads.emplace_back([i, &thread_completed, &mtx, &cv, &completed_num]() {
            // 模拟任务执行
            std::this_thread::sleep_for(std::chrono::seconds(i + 1));
            
            // 任务完成,更新状态并通知主线程
            std::lock_guard<std::mutex> lock(mtx);
            thread_completed[i] = true;
            completed_num++;
            cv.notify_one();
        });
    }

    // 主线程等待任意线程完成并回收
    while (completed_num > 0) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [&completed_num]() { return completed_num > 0; });

        // 遍历处理已完成的线程
        for (int i = 0; i < thread_count; ++i) {
            if (thread_completed[i] && threads[i].joinable()) {
                std::cout << "线程 " << i << " 已完成,回收资源" << std::endl;
                threads[i].join();
                thread_completed[i] = false;
                completed_num--;
            }
        }
    }

    std::cout << "所有线程处理完毕" << std::endl;
    return 0;
}

方案二:std::future+非阻塞轮询(灵活)

利用 std::future 的 wait_for 方法实现非阻塞检查,适合主线程需要同时执行其他任务的场景。

实现逻辑

  1. 用 std::async 创建异步任务,获取对应的 std::future 对象;
  2. 主线程循环调用 wait_for 检查每个 future 的状态,若某线程任务完成则调用 get() 回收资源;
  3. 直到所有线程处理完毕。

示例代码

#include <iostream>
#include <vector>
#include <future>
#include <chrono>

int main() {
    const int thread_count = 3;
    std::vector<std::future<void>> futures;

    // 创建异步任务
    for (int i = 0; i < thread_count; ++i) {
        futures.emplace_back(std::async(std::launch::async, [i]() {
            std::this_thread::sleep_for(std::chrono::seconds(i + 1));
            std::cout << "线程 " << i << " 完成任务" << std::endl;
        }));
    }

    // 非阻塞轮询检查线程状态
    bool all_done = false;
    while (!all_done) {
        all_done = true;
        for (auto& fut : futures) {
            if (fut.valid()) {
                auto status = fut.wait_for(std::chrono::milliseconds(100));
                if (status == std::future_status::ready) {
                    fut.get(); // 回收已完成的任务资源
                    std::cout << "已回收一个完成的线程" << std::endl;
                } else {
                    all_done = false;
                }
            }
        }
    }

    std::cout << "所有线程处理完毕" << std::endl;
    return 0;
}

关键注意事项

  • 方案一基于条件变量,是阻塞式等待第一个完成的线程,CPU利用率更低,适合对性能敏感的场景;
  • 方案二是非阻塞轮询,需要合理设置轮询间隔,避免过度占用CPU;
  • 无论哪种方案,都必须调用 join() 或 get() 回收线程资源,防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:28:34