Jack Simpson
Jack Simpson

Reputation: 1711

Variable number of async threads with C++11

I'm working on a program where I'd like to use async in a loop. In the example code I've included there's only 10 elements, so I could easily create an explicit variable for each element. However, in my main program, the number of elements in the vector can vary. Ideally, I'd like to create a vector of async threads - one for every element in the array - which are pushed back on the async vector as I loop through.Then I want to wait for them all to complete, and then use "get()" to return all of their outputs.

The code below will call async by assigning an explicit variable for each thread, but does anyone know how to dynamically call async in a vector without having to explicitly assign a variable to it? Ideally, I'd like for this program to call "std::cout" once for each time it looped through, instead of just once.

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

std::string hi (std::string input)
{
    return "hello, this is " + input;
}

int main()
{
    std::vector<std::string> test_vector( 10, "a test" );
    std::future<std::string> a;
    std::future<std::string> b;

    for ( int i = 0; i < test_vector.size ( ); i++ )
    {
        a = std::async(std::launch::async, hi, test_vector[i]);
    }

    std::cout << a.get() << std::endl;

    return 0;
 }

Upvotes: 10

Views: 4115

Answers (3)

Galik
Galik

Reputation: 48615

You can solve this by creating a vector of futures to match your threads vector, something like this:

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

std::string hi(const std::string& input)
{
    return "hello, this is " + input;
}

int main()
{
    std::vector<std::string> tests = {"one", "two", "three", "four"};
    std::vector<std::future<std::string>> futures;

    // add the futures to the futures vector as you launch
    // your asynchronous functions
    for(auto&& t: tests)
        futures.emplace_back(std::async(std::launch::async, hi, std::cref(t)));

    // collect your results
    for(auto&& f: futures)
        std::cout << f.get() << '\n';
}

Note the use of std::cref to pass by const reference. Use std::ref to pass non const references.

Upvotes: 15

GChamon
GChamon

Reputation: 476

If I understood correctly, could be something like:

std::vector<std::future<std::string>> vessel;
for ( int i = 0; i < test_vector.size ( ); i++ )
{
    std::future<std::string> aux;
    aux = std::async(std::launch::async, hi);
    vessel.push_back(aux);
}

Sorry I cannot post as a comment, but this way, depending on the logic, and if it works, then you should be able to dynamically manipulate the vector vessel.


Update

better yet:

vessel.push_back(new std::future<std::string>);
vessel[vessel.size()-1] = std::async(std::launch::async, hi);

this way you don't need to explicitly declare a variable. But you will have to delete once you are done:

for(int i=0; i<(int) vessel.size(); i++)
{
    delete vessel[i];
}

Upvotes: 3

ALittleDiff
ALittleDiff

Reputation: 1211

An answer including std::cout:

std::vector<std::future<std::string>> a;
for (int i = 0; i < 10; ++i) {
  a.emplace_back(std::async(hi));
}
for (auto& element : a) {
  std::cout << element.get() << std::endl;
}

Upvotes: 11

Related Questions