线程池必须支持任务返回值,核心是用std::packaged_task封装可调用对象并配合std::future获取结果;任务队列需用std::queue<std::packaged_task<T()>>配合std::move;线程空闲时应使用带超时的cv.wait_for配合yield避免忙等或丢唤醒;提交后必须调用future的get()或wait(),否则析构时会阻塞。

线程池必须带任务返回值,否则无法满足实际需求
直接用 std::thread 启动任务没法拿返回值,必须靠包装 + 同步机制。核心思路是:每个任务封装成 std::packaged_task,通过 std::future 拿结果。别试图手动管理线程+回调+队列再拼返回值——容易丢异常、漏等待、线程不安全。
用 std::packaged_task 包装任意可调用对象
这是最稳妥的返回值支持方式。它把函数对象和 promise 绑定在一起,执行时自动触发 future 就绪。
-
std::packaged_task<int()>可以包装返回int的无参 lambda、函数指针或仿函数 - 构造时传入 callable,调用
task()即执行并设置 future 状态 - 不能复制,只能移动;所以任务队列要用
std::queue<std::packaged_task<T()>>+std::move - 如果任务抛异常,
future.get()会 rethrow,不用额外 try-catch
线程循环里必须用 std::this_thread::yield() 或超时等待
空闲时忙等(while(!task) {})会吃满一个 CPU 核;但只用 std::condition_variable::wait() 又可能错过唤醒信号。标准解法是带超时的 wait,配合 yield 避免锁竞争。
- 用
cv.wait_for(lock, 100ms, [&]{ return !tasks.empty(); })替代无限 wait - 若超时且队列仍空,调用
std::this_thread::yield()让出时间片 - 不要在 wait 前加 while 循环检查 empty() —— 条件变量已内置原子检查
- 注意:
wait_for返回 false 不代表没任务,可能是虚假唤醒,必须配合谓词判断
提交任务后立即获取 std::future,但别忘了 get() 或 wait()
future 是唯一访问返回值的入口,但忘记调用 get() 或 wait() 会导致线程阻塞在析构(C++11 起,std::future 析构时若未就绪会阻塞)。
立即学习“C++免费学习笔记(深入)”;
- 提交任务:
auto fut = pool.submit([]{ return 42; }); - 后续必须
fut.get()(阻塞取值)或fut.wait()(仅同步) - 多个 future 可用
std::vector<std::future<int>>存储,再统一wait() - 若任务可能长时间运行,建议用
wait_for()防止卡死
线程池本身不负责 future 生命周期,谁 submit 谁负责 get —— 这点容易被忽略,尤其在异步链式调用中。


















