po.pe
po.pe

Reputation: 1162

Future returned by a function

I try to understand the concept of future and promise but have some issues to use them as return values from functions.

I came up with the code below

#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();
}

So main should create a future from the return value of func, wait for the future to be assigned and then print it. But when I execute it, A is constructed and destructed without the thread being executed. Could someone guide me to the right direction?

edit

I added the vector containing the different promises. The thread doesn't directly process the promise but calls the processQueue function to do it. The class A object is created once and a unique_ptr reference is handed to the function where it's required.

#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;
}

Upvotes: 0

Views: 536

Answers (1)

ph&#246;n
ph&#246;n

Reputation: 1255

2 problems:

  1. You are destructing your thread object in A before the thread can get detached. You could for example detach the thread in the A destructor, so control flow will reach it before A is completly destructed.

  2. The lambda in your thread object is working on the promise which is only alive in the func function scope. As soon as control flow leaves this scope, your promise get destructed and throws a broken promise exception. To prevent that, your lambda function should take ownership of the promise. If it takes ownership, you have to make sure to get the future before the ownership movement.

This leads to the following code (i just removed your errors. whether its a good design is another question ;-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;
}

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

Upvotes: 3

Related Questions