何时使用async或packaged_task的承诺?

Dom*_*ins 42 c++ asynchronous future promise packaged-task

我应该什么时候使用std::promisestd::asyncstd::packaged_task?你能告诉我何时使用它们的实际例子吗?

use*_*016 50

的std ::异步

std::async得到一个简洁明了的方法std::future,但是:

  • 它并不总是启动一个新线程; 传递std::launch::async作为第一个参数来强制它.

    auto f = std::async( std::launch::async, func );
    
    Run Code Online (Sandbox Code Playgroud)
  • std::~future析构函数可以阻止,直到新线程完成

    auto sleep = [](int s) { std::this_thread::sleep_for(std::chrono::seconds(s)); };
    
    {
        auto f = std::async( std::launch::async, sleep, 5 );
    }
    
    Run Code Online (Sandbox Code Playgroud)

    通常我们期望只有.get().wait()块,但是对于std::future返回std::async的析构函数也可能会阻塞,所以注意不要仅仅因为忘记它而阻止你的主线程.

  • 如果std::future存储在临时生命对象中,则std::async调用将立即阻止,因此如果删除初始化,则以下块将花费10秒auto f =:

    auto sleep = [](int s) { std::this_thread::sleep_for(std::chrono::seconds(s)); };
    
    {
        auto f1 = std::async( std::launch::async, sleep, 5 );
        auto f2 = std::async( std::launch::async, sleep, 5 );
    }
    
    Run Code Online (Sandbox Code Playgroud)

的std :: packaged_task

std::packaged_task它本身与线程无关:它只是一个仿函数和一个相关的std::future.考虑以下:

auto task = [](int i) { std::this_thread::sleep_for(std::chrono::seconds(5)); return i+100; };

std::packaged_task< int(int) > package{ task };
std::future<int> f = package.get_future();
package(1);
std::cout << f.get() << "\n";
Run Code Online (Sandbox Code Playgroud)

在这里我们只运行任务package(1),并在它返回后,f准备就绪,因此没有阻塞.get().

有一个特性std::packaged_task使它对线程非常有用.您可以std::thread使用a 初始化而不仅仅是一个函数,std::packaged_task它提供了一种非常好的方式来获取'std :: future'.考虑以下:

std::packaged_task< int(int) > package{ task };
std::future<int> f = package.get_future();
std::thread t { std::move(package), 5 };

std::cout << f.get() << "\n";       //block here until t finishes

t.join();
Run Code Online (Sandbox Code Playgroud)

因为std::packaged_task不可复制,所以必须将其移动到新线程std::move.

的std ::承诺

std::promise是一种强大的机制.例如,您可以将值传递给新线程,而无需任何其他同步.

auto task = [](std::future<int> i) {
    std::cout << i.get() << std::flush;
};

std::promise<int> p;
std::thread t{ task, p.get_future() };

std::this_thread::sleep_for(std::chrono::seconds(5));
p.set_value(5);

t.join();
Run Code Online (Sandbox Code Playgroud)

新线程将等待我们 .get()


所以,一般来说,回答你的问题:

  • 使用std::async仅用于简单的事情,比如做一些通话无阻塞,但牢记评论上面阻塞.
  • 使用std::packaged_task轻松搞定一个std::future,并运行它作为一个单独的线程

    std::thread{ std::move(package), param }.detach();
    
    Run Code Online (Sandbox Code Playgroud)

    要么

    std::thread t { std::move(package), param };
    
    Run Code Online (Sandbox Code Playgroud)
  • std::promise当您需要对未来进行更多控制时使用.

另请参见std::shared_future并在线程之间传递异常std::promise::set_exception


Kla*_*end -1

Promise 用于存储使用 std::async 等计算得出的值。请参阅http://en.cppreference.com/w/cpp/thread/promise

我可以想象您想知道 std::packaged_task 和 std::async 之间的区别(在最常见的方法中,std::async 现在启动一个单独的线程来运行函数/lambda/等,并进行(可能)昂贵的计算。 std::packaged_task 用于使用参数的当前值包装函数/lambda/等,以便您稍后可以同步或在单独的线程中运行它。

std::packaged_task 和 std::async 都提供了一个 std::future ,一旦运行,它将包含包装函数/lambda/等的结果。在内部, std::future 使用 std::promise 来保存该结果。

  • `std::future` 和 `std::promise` 具有“共享状态”,因此结果不存储在 Promise 对象中,而是存储在共享状态中 (2认同)