C++中如何同时等待多线程?是否存在非阻塞join实现thread_select?
C++ 实现类似
select() 的多线程等待方案 C++ 标准库没有直接提供类似 select() 的多线程等待接口,也不存在非阻塞版本的 join(),但可以通过以下两种方案实现类似 thread_select 的需求——让主线程等待任意一个子线程完成,而非固定等待某一个。
方案一:条件变量+状态标记(阻塞式,高效)
通过追踪线程完成状态,配合条件变量实现主线程的精准唤醒,避免无意义的CPU消耗。
实现逻辑
- 为每个子线程维护一个原子状态标记,记录其是否完成任务;
- 子线程完成任务后,更新自身状态并唤醒主线程;
- 主线程阻塞在条件变量上,直到有线程完成,随后遍历状态标记找到已完成的线程,调用
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 方法实现非阻塞检查,适合主线程需要同时执行其他任务的场景。
实现逻辑
- 用
std::async创建异步任务,获取对应的std::future对象; - 主线程循环调用
wait_for检查每个future的状态,若某线程任务完成则调用get()回收资源; - 直到所有线程处理完毕。
示例代码
#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
相关产品推荐
相关产品推荐

