c++ - 为什么 std::future 从 std::packaged_task 和 std::async 返回的不同?

标签 c++ c++14 stdasync packaged-task std-future

我才知道原因futurestd::async 返回有一些特殊的共享状态,通过它 wait on returned future发生在 future 的析构函数中。但是当我们使用 std::pakaged_task ,它的 future 不会表现出相同的行为。
要完成打包任务,您必须明确调用 get()future来自 packaged_task 的对象.
现在我的问题是:

  • future 的内部实现可能是什么(思考 std::async vs std::packaged_task )?
  • 为什么相同的行为没有应用于 futurestd::packaged_task 返回?或者,换句话说,对于 std::packaged_task 相同的行为是如何停止的? future ?

  • 要查看上下文,请查看以下代码:
    它不等待完成countdown任务。但是,如果我取消评论 // int value = ret.get(); ,它会完成 countdown并且很明显,因为我们实际上是在阻止返回的 future 。
        // packaged_task example
    #include <iostream>     // std::cout
    #include <future>       // std::packaged_task, std::future
    #include <chrono>       // std::chrono::seconds
    #include <thread>       // std::thread, std::this_thread::sleep_for
    
    // count down taking a second for each value:
    int countdown (int from, int to) {
      for (int i=from; i!=to; --i) {
        std::cout << i << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(1));
      }
      std::cout << "Lift off!" <<std::endl;
      return from-to;
    }
    
    int main ()
    {
       std::cout << "Start " << std::endl;
      std::packaged_task<int(int,int)> tsk (countdown);   // set up packaged_task
      std::future<int> ret = tsk.get_future();            // get future
    
      std::thread th (std::move(tsk),10,0);   // spawn thread to count down from 10 to 0
    
    //   int value = ret.get();                  // wait for the task to finish and get result
    
      std::cout << "The countdown lasted for " << std::endl;//<< value << " seconds.\n";
    
      th.detach();   
    
      return 0;
    }
    
    如果我使用 std::async执行任务 countdown在另一个线程上,无论我是否使用 get()在返回 future对象与否,它将始终完成任务。
    // packaged_task example
    #include <iostream>     // std::cout
    #include <future>       // std::packaged_task, std::future
    #include <chrono>       // std::chrono::seconds
    #include <thread>       // std::thread, std::this_thread::sleep_for
    
        // count down taking a second for each value:
        int countdown (int from, int to) {
          for (int i=from; i!=to; --i) {
            std::cout << i << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
          }
          std::cout << "Lift off!" <<std::endl;
          return from-to;
        }
        
        int main ()
        {
           std::cout << "Start " << std::endl;
          std::packaged_task<int(int,int)> tsk (countdown);   // set up packaged_task
          std::future<int> ret = tsk.get_future();            // get future
        
          auto fut = std::async(std::move(tsk), 10, 0);   
    
        
        //   int value = fut.get();                  // wait for the task to finish and get result
        
          std::cout << "The countdown lasted for " << std::endl;//<< value << " seconds.\n";
    
          return 0;
        }
    

    最佳答案

    std::async对所给任务的执行方式和地点有明确的了解。那就是它的工作:执行任务。要做到这一点,它实际上必须把它放在某个地方。某个地方可能是一个线程池,一个新创建的线程,或者在一个被破坏 future 的人执行的地方。 .
    因为 async知道函数将如何执行,它拥有构建一种机制所需的 100% 的信息,该机制可以在潜在的异步执行结束时进行通信,并确保如果您破坏了 future ,那么将执行该函数的任何机制最终都会实际执行它。毕竟,它知道那个机制是什么。
    但是packaged_task没有。全部 packaged_task do 是存储一个可以使用给定参数调用的可调用对象,创建一个 promise与函数返回值的类型,并提供一种方法来获得 future并执行生成值的函数。
    任务实际执行的时间和地点不是 packaged_task的事。如果没有这些知识,同步需要做 future的析构函数与任务同步根本无法构建。
    假设您想在新创建的线程上执行任务。好的,因此将其执行与 future 同步的破坏,你需要一个互斥锁,析构函数将阻塞它直到任务线程完成。
    但是如果你想在与 future 的调用者相同的线程中执行任务怎么办?的析构函数?那么,你不能使用互斥锁来同步它,因为它都在同一个线程上。相反,您需要让析构函数调用任务。这是一种完全不同的机制,取决于您计划如何执行。
    因为 packaged_task不知道您打算如何执行它,它无法执行任何操作。
    请注意,这不是 packaged_task 独有的。 .全部 future从用户创建的 promise 创建的对象将不具有 async 的特殊属性的 future s。
    所以问题真的应该是为什么async以这种方式工作,而不是为什么其他人不这样做。
    如果你想知道,那是因为两个相互竞争的需求:async需要是一种高级的、脑死亡的简单方法来获得异步执行(对于这种情况下同步销毁是有意义的),并且没有人想要创建一个新的 future除了其析构函数的行为外,类型与现有类型相同。所以他们决定如何重载future工作,使其实现和使用复杂化。

    关于c++ - 为什么 std::future 从 std::packaged_task 和 std::async 返回的不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63843676/

    相关文章:

    c++ - 如何获取视频采集设备信息?

    c++ - sf::RenderWIndows的 vector

    c++ - 如何将变量传递给 std::async?

    c++ - std::thread 到 std::async 会带来巨大的性能提升。怎么可能?

    c++ - malloc() 与 new[] 的内存开销

    c++ - 如何使用 RapidXML C++ 检查 xml 中的空标记

    接口(interface) ptr 的 C++ 返回 vector

    c++ - 长时间运行的 std::async 会饿死其他 std::async 吗?

    c++ - 收听 UDP 广播

    c++ - 在C++中,如何使用在另一个文件中定义的常量变量?