首页 > 解决方案 > 函数返回的未来

问题描述

我试图理解的概念,futurepromise有一些问题将它们用作函数的返回值。

我想出了下面的代码

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

std::future<int> func(int i);

class A{
public:
    A(std::promise<int> && prms, int i):thread_([&]{
        std::cout << "Thread created in A\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        prms.set_value(i*2);
        thread_.detach();
    }){std::cout << "Call constructor of A\n";}
    ~A(){std::cout << "Call A's Destructor\n";}

private:
std::thread thread_;
};

int main()
{
    auto a_inst = func(2);
    a_inst.wait();
    std::cout << a_inst.get() << std::endl;

}

std::future<int> func(int i){
    std::promise<int> prms;
    //std::future<int> ftr = prms.get_future();
    A A1(std::move(prms), i);
    return prms.get_future();
}

所以main应该从 的返回值创建一个未来func,等待未来被分配然后打印它。但是当我执行它时,A在没有执行线程的情况下被构造和破坏。有人可以指导我正确的方向吗?

编辑

我添加了包含不同的向量promises。线程不直接处理,promise而是调用processQueue函数来完成。类A对象被创建一次,unique_ptr 引用被传递给需要它的函数。

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

class A{
public:
    int element_pointer = 0;
    A():thread_([&]() {
        std::cout << "Thread created in A\n";
        for(;;){
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            processQueue();
        }
        //local_promise.set_value(local_i*2);
    })
    {
        std::cout << "Call constructor of A\n";
    }

    ~A(){
        thread_.detach();
        std::cout << "Call A's Destructor\n";
    }

    void enq(std::promise<int> prms){
        std::lock_guard<std::mutex> guard(m);
        local_prmses_.push_back(std::move(prms));
        std::cout << "Queue now holds " << local_prmses_.size() << " elements\n";
    }

private:
    std::thread thread_;
    std::mutex m;
    std::vector<std::promise<int>> local_prmses_;
    void processQueue(){
        std::lock_guard<std::mutex> guard(m);
        std::cout << "execute processQueue()" << std::endl;
            if(element_pointer < local_prmses_.size()){
                for(element_pointer; element_pointer<local_prmses_.size(); element_pointer++){
                    local_prmses_[element_pointer].set_value(6);
                    std::cout << "Promise assigned\n";
                }

            } else {
                std::cout << "Nothing to process" << std::endl;
            }
        }
};

std::future<int> func(std::unique_ptr<A>& obj, int i);

int main()
{
    std::unique_ptr<A> obj = std::make_unique<A>();
    auto futr = func(obj, 9);
    //a_inst.wait();
    //std::cout << a_inst.get() << std::endl;
    for(;;){
        std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        if(futr.valid()){
            std::cout << "Yepeee!\n";
            std::cout << "Result is " << futr.get() << std::endl;
        }
        std::cout << "waiting...\n";
    }
}

std::future<int> func(std::unique_ptr<A>& obj, int i){
    std::promise<int> prms;
    auto fut = prms.get_future();
    obj->enq(std::move(prms));
    return fut;
}

标签: c++multithreadingpromisefuture

解决方案


2个问题:

  1. A在线程可以分离之前,您正在破坏您的线程对象。例如,您可以分离 A 析构函数中的线程,因此控制流将在 A 被完全破坏之前到达它。

  2. 您的线程对象中的 lambda 正在处理仅在func函数范围内有效的承诺。一旦控制流离开这个范围,你的 Promise 就会被破坏并抛出一个损坏的 Promise 异常。为防止这种情况发生,您的 lambda 函数应获得承诺的所有权。如果它需要所有权,您必须确保在所有权运动之前获得未来。

这导致以下代码(我刚刚删除了您的错误。它是否是一个好的设计是另一个问题;-P):

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

std::future<int> func(int i);

class A{
public:
    A(std::promise<int> prms, int i):thread_([local_promise = std::move(prms), local_i = i]() mutable {
        std::cout << "Thread created in A\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        local_promise.set_value(local_i*2);
    })
    {
        std::cout << "Call constructor of A\n";
    }

    ~A(){
        thread_.detach();
        std::cout << "Call A's Destructor\n";
    }

private:
std::thread thread_;
};


int main()
{
    auto a_inst = func(9);
    a_inst.wait();
    std::cout << a_inst.get() << std::endl;
}

std::future<int> func(int i){
    std::promise<int> prms;
    auto fut = prms.get_future();
    A A1(std::move(prms), i);
    return fut;
}

直播:http ://coliru.stacked-crooked.com/a/8e2a3b982ad6e9fb


推荐阅读