Home > Software design >  Let main thread wait async threads complete
Let main thread wait async threads complete

Time:11-07

I'm new to c and don't know how to let main thread wait for all async threads done. I refered this but makes void consume() not parallel.

#include <iostream>
#include <vector>
#include <unistd.h>     // sleep
#include <future>

using namespace std;

class Myclass {
private:
    std::vector<int> resources;
    std::vector<int> res;

    std::mutex resMutex;
    std::vector<std::future<void>> m_futures;
public:
    Myclass() {
        for (int i = 0; i < 10; i  ) resources.push_back(i);   // add task
        res.reserve(resources.size());
    }

    void consume() {
        for (int i = 0; i < resources.size(); i  ) {
            m_futures.push_back(std::async(std::launch::async, &Myclass::work, this, resources[i]));
//            m_futures.back().wait();
        }
    }

    void work(int x) {
        sleep(1);     // Simulation time-consuming

        std::lock_guard<std::mutex> lock(resMutex);
        res.push_back(x);
        printf("%d be added.---done by %d.\n", x, std::this_thread::get_id());
    }

    std::vector<int> &getRes() { return res;}
};

int main() {
    Myclass obj;
    obj.consume();
    auto res = obj.getRes();
    cout << "Done. res.size = " << res.size() << endl;
    for (int i : res) cout << i << " ";
    cout <<"main thread over\n";
}

Main thread ends up when res = 0. I want obj.getRes() be be executed when all results be added into res.

Done. res.size = 0
main thread over
4 be added.---done by 6.
9 be added.---done by 11...

CodePudding user response:

You had the right idea with the commented out line: m_futures.back().wait();, you just have it in the wrong place.

As you note, launching a std::async and then waiting for its result right after, forces the entire thing to execute in series and makes the async pointless.

Instead you want two functions: One, like your consume() that launches all the async's, and then another that loops over the futures and calls wait (or get, whatever suits your needs) on them - and then call that from main.

This lets them all run in parallel, while still making main wait for the final result.

CodePudding user response:

Addition to @Frodyne 's answer, consume() function calls are parallel, and main thread waits for the all consume() s have their work done;

 void set_wait(void)
    {
        for (int i = 0; i < resources.size(); i  ) {
            m_futures[i].wait();
        }
    }

And call it here

    void consume() {
        for (int i = 0; i < resources.size(); i  ) {
            m_futures.push_back(std::async(std::launch::async, &Myclass::work, this, resources[i]));
             // Calling wait() here makes no sense
        }
        set_wait(); // Waits for all threads do work
    }

I created new function for convenience.

CodePudding user response:

You can use std::future:wait after you add task to m_futures. Example.

void consume() {
    for (int i = 0; i < resources.size(); i  ) {
        m_futures.push_back(std::async(std::launch::async, &Myclass::work, this, resources[i]));
          //m_futures.back().wait();
    }
    for(auto& f: m_futures) f.wait();
}
  • Related