函数返回的未来

时间:2018-08-13 12:09:54

标签: c++ multithreading promise future

我尝试理解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的返回值创建一个Future,等待赋值Future,然后打印它。 但是当我执行它时,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;
}

1 个答案:

答案 0 :(得分:3)

2个问题:

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

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

这将导致以下代码(我刚刚删除了您的错误。它的良好设计是否是另一个问题;-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