1

In using packaged_task, I collected all the futures in a vector. After that, I push back the future values with get(). However, I got the wrong answer. Can anyone help? Thank you very much.

#define BOOST_THREAD_PROVIDES_FUTURE

#include <boost/thread/future.hpp>
#include <vector>
#include <iostream>

using namespace std;

vector<int> subFun(int n) {

    vector<int> a{ 2 * n, 3 * n };

    return a;
}

int main() {

    vector<boost::future<vector<int>>> g;
    vector<vector<int>> x(10, vector<int>(2));
    int i;

    for (i = 0; i < 10; i++) {
        boost::packaged_task<vector<int>> task{ boost::bind(&subFun, i) };
        g.push_back(task.get_future());
        boost::thread t{ std::move(task) };
    }

    for (auto& m : g) {
        x.push_back(m.get());
    }

    cout << x[3][0] << endl;//should be 6, now is 0

    return 0;
}
Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
Frankie
  • 744
  • 1
  • 9
  • 14

2 Answers2

0

After much tinkering, I found this program works without abort traps (which I'm surprised you weren't getting):

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

std::vector<int> subFun(int n) {

    std::vector<int> a { 2 * n, 3 * n };

    return a;
}

int main() {

    std::vector<std::future<std::vector<int>>> g;
    std::vector<std::vector<int>> x;

    int i;

    for (i = 0; i < 10; i++) {
        std::packaged_task<std::vector<int>(int)> task{ subFun };
        g.push_back(task.get_future());
        std::thread { std::move(task), i }.detach();
    }

    for (auto& m : g) {
        m.wait();
        x.push_back(m.get());
    }

    std::cout << x[3][0] << std::endl; // is now 6

    return 0;
}

Convert to boost as necessary. This answer was extremely helpful in finding a couple of key issues.

Community
  • 1
  • 1
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • Thanks. I added m.wait(), but the result is still 0 instead of 6. – Frankie May 19 '17 at 04:19
  • The abort traps could be due to (unrelated) race where `main` ends before the threads disappear. Unjoined threads trigger abnormal program termination unless detached. – sehe May 19 '17 at 08:41
  • Thank you very much for all your answers. I have a clearer picture on future. – Frankie May 20 '17 at 09:28
0

The realest issue is that you push_back into x, but you already had it initialized here:

vector<vector<int>> x(10, vector<int>(2));

So, you just add 10 more elements, instead of putting the result at indices 0..9. I'd suggest not pre-filling, like @patrick's answer, or instead filling the designated slot:

#define BOOST_THREAD_PROVIDES_FUTURE

#include <boost/thread/future.hpp>
#include <vector>
#include <iostream>

using namespace std;

void subFun(int n, vector<int>& into) {
    into = { 2 * n, 3 * n };
}

int main() {
    vector<boost::future<void>> futures;
    vector<vector<int>> x(10, vector<int>(2));

    for (size_t i = 0; i < x.size(); i++) {
        boost::packaged_task<void> task{ boost::bind(&subFun, i, std::ref(x[i])) };
        futures.push_back(task.get_future());
        boost::thread(std::move(task)).detach();
    }

    for (auto& f : futures)
        f.wait();

    cout << x[3][0] << endl;
}

Of course you can be more complex:

#define BOOST_THREAD_PROVIDES_FUTURE

#include <boost/thread/future.hpp>
#include <vector>
#include <iostream>

struct TaskResult {
    int index;
    std::vector<int> data; 
};

TaskResult subFun(int n) {
    return { n, { 2 * n, 3 * n } };
}

int main() {
    std::vector<boost::future<TaskResult>> futures;
    std::vector<std::vector<int>> x(10, std::vector<int>(2));

    for (size_t i = 0; i < x.size(); i++) {
        boost::packaged_task<TaskResult> task{ boost::bind(&subFun, i) };
        futures.push_back(task.get_future());
        boost::thread(std::move(task)).detach();
    }

    for (auto& f : futures) {
        auto r = f.get();
        x[r.index] = r.data;
    }

    std::cout << x[3][0] << std::endl;
}
sehe
  • 374,641
  • 47
  • 450
  • 633