更换的std ::异步与自己的版本,但应该在哪里标准::承诺住?(Replacing std::as

2019-07-29 00:45发布

我使用vc2011和原来的标准::异步(STD ::推出::异步,...)是有点马车(有时不产生新的线程,并运行它们平行,而是重用线程和运行任务一个接一个)。 这是太慢了,当我做昂贵的网络电话。 所以,我想我会写我自己的异步功能。 我越来越虽然卡住,应该在哪里标准::答应住? 在1)的线程的功能,2)异步函数,或3)调用者函数。

码:

#include <future>
#include <thread>
#include <iostream>
#include <string>
#include <vector>

std::string thFun() {
    throw std::exception("bang!");
    return "val";
}

std::future<std::string> myasync(std::promise<std::string>& prms) {
//std::future<std::string> myasync() {
    //std::promise<std::string> prms; //needs to outlive thread. How?

    std::future<std::string> fut = prms.get_future();
    std::thread th([&](){
        //std::promise<std::string> prms; //need to return a future before...
        try {
            std::string val = thFun();

            prms.set_value(val);

        } catch(...) {
            prms.set_exception(std::current_exception());
        }

     });

    th.detach();
    return fut;
}

 int main() {

    std::promise<std::string> prms; //I really want the promise hidden iway in the myasync func and not live here in caller code but the promise needs to outlive myasync and live as long as the thread. How do I do this?
    auto fut = myasync(prms);

    //auto fut = myasync(); //Exception: future already retrieved

    try {
        auto res = fut.get();
        std::cout << "Result: " << res << std::endl;

    } catch(const std::exception& exc) {
        std::cout << "Exception: " << exc.what() << std::endl;
    }

 }

我似乎无法让过去的标准::承诺需要活得比异步性的作用(只要线程活着),所以承诺不能作为生活在异步FUNC一个局部变量。 但在主叫用户代码的std ::承诺不应该住在任,作为主叫方只需要了解期货。 ,我不知道如何使承诺住在线程函数作为异步需要返回一个未来它甚至调用线程FUNC之前。 我抓我的头就这一个。

任何人有什么想法?

编辑:我在这里强调这是上面的评论是有点误导。 虽然标准:: asycn默认被允许成为dererred模式下,当的std ::推出的启动策略::异步明确设置它必须表现得“好像”线程启动,并同时运行(见措辞EN .cppreference.com / W / CPP /线程/异步)。 参见一个情况下,这不是在vs20011看到behavioured在pastebin.com/5dWCjjNY的例子。 该解决方案的伟大工程,以10倍加速了我的现实世界的应用程序。

编辑2:MS固定在错误。 更多资讯: https://connect.microsoft.com/VisualStudio/feedback/details/735731/std-async-std-launch-async-does-not-behave-as-std-thread

Answer 1:

这里是一个解决方案:

future<string> myasync()
{
    auto prms = make_shared<promise<string>> ();

    future<string> fut = prms->get_future();

    thread th([=](){

        try {
            string val = thFun();
            // ...
            prms->set_value(val);

        } catch(...) {
            prms->set_exception(current_exception());
        }

     });

    th.detach();

    return fut;
}

在堆上分配承诺,然后通过按值[=]通过对拉姆达一个shared_ptr给它。



Answer 2:

您需要将承诺迁入新的线程。 安德鲁Tomazos的回答做它通过创建一个std::promise与共享所有权,那么这两个线程可以根据自己的承诺,并且在当前一个从目前的范围只返回新的线程拥有的承诺,即所有权已经转移。 但是, std::promise是可移动的,所以应该是可以直接移动到它的新的线程,除了夺取它不起作用,因为拉姆达的不能移动捕捉,只能通过副本的“明显”的解决方案(或引用,你会得到一个悬挂引用这是行不通的。)

但是, std::thread支持传递右值对象,新线程的启动功能。 所以你可以声明拉姆达采取std::promise的价值,即参数传递的promise ,以拉姆达而不是捕捉它,然后将承诺转变成的其中一个参数std::thread

std::future<std::string> myasync() {
    std::promise<std::string> prms;

    std::future<std::string> fut = prms.get_future();
    std::thread th([&](std::promise<std::string> p){
        try {
            std::string val = thFun();

            p.set_value(val);

        } catch(...) {
            p.set_exception(std::current_exception());
        }

     }, std::move(prms));

    th.detach();
    return fut;
}

此举承诺到std::thread对象,然后移动它(在新线程的上下文中)到拉姆达的参数p



文章来源: Replacing std::async with own version but where should std::promise live?