关于延迟任务对象的技术问询:唤醒不调用future<T>.get()及wait_for行为
嘿,这两个问题都是C++异步编程里关于延迟任务的典型困惑,我来给你逐一拆解清楚:
问题1:如何唤醒延迟任务对象,且无需调用future.get()?
首先得明确:用std::async(std::launch::deferred, ...)创建的延迟任务,只会在你主动触发它的时候才会执行,而触发的方式不止get()一种——你可以直接调用std::future::wait()方法。
wait()的作用是:触发延迟任务在当前线程执行,直到任务完全完成,并且它不会返回任务的结果,刚好满足你“唤醒任务但不用get()”的需求。- 注意别搞混:
wait_for()或者wait_until()如果传入零时长(比如std::chrono::seconds(0)),只会检查任务的状态,不会触发任务执行;只有wait()、get(),或者当你调用wait_for()/wait_until()且任务已经被触发过的时候,才会等待任务完成。
举个简单的例子:
#include <future> #include <iostream> void deferred_task() { std::cout << "任务执行中..." << std::endl; } int main() { auto fut = std::async(std::launch::deferred, deferred_task); // 用wait()唤醒任务,不用get() fut.wait(); return 0; }
问题2:当对延迟任务对象调用std::future::wait_for时,会产生怎样的行为?理想状态下,我希望唤醒延迟任务,但不在当前线程中承担任务处理的开销。
先讲wait_for()的行为:对于延迟任务来说,调用wait_for()不管你指定多长的超时时间,都会立即返回std::future_status::deferred,完全不会触发任务执行。这是C++标准明确规定的,因为延迟任务的设计初衷就是“延迟到显式调用wait/get时才在当前线程执行”。
那你想要的“唤醒任务但不让当前线程承担处理开销”的需求,其实和延迟任务的设计初衷有点冲突——因为延迟任务本身就是绑定到调用wait/get的线程上执行的。要实现你的需求,有两种可行的方式:
一开始就用异步策略创建任务:
如果你从一开始就希望任务在后台线程执行,不要用std::launch::deferred,而是用std::launch::async。这样任务会立即在一个新的后台线程启动,不需要你主动唤醒,当前线程也不会承担任务的执行开销:auto fut = std::async(std::launch::async, [](){ /* 你的任务 */ }); // 任务已经在后台跑了,当前线程该干嘛干嘛把延迟任务的触发放到其他线程:
如果你已经有了一个延迟任务的future,想要让它在后台线程执行,你可以把wait()或者get()的调用放到一个新线程里,让任务在那个线程中运行:auto deferred_fut = std::async(std::launch::deferred, [](){ /* 你的任务 */ }); // 创建一个新线程来触发任务 std::thread task_thread([&](){ deferred_fut.wait(); }); // 如果你不需要等待任务完成,可以detach线程;如果需要等待就调用join() task_thread.detach();这样,任务的执行就会在
task_thread里完成,当前线程不会被占用,也不会承担任务的处理开销。
内容的提问来源于stack exchange,提问作者Ram

