notify from a private vector of objects
Aug 25, 2017 at 2:20pm UTC
I have a class , "request", which has a vector of "exector" objects. Each executor object executes something asynchronously.
How can I find out if at least one of the executors has completed?
This is a skeleton of the two classes ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#include <memory>
#include <chrono>
#include <iostream>
#include <vector>
#include <condition_variable>
#include <thread>
#include <future>
#include <cstdlib>
class executor {
private :
bool is_complete {false };
int exec_id ;
public :
executor(int eid) : exec_id{eid} { }
void execute_something() {
std::srand(std::time(0));
int seconds_delay = (std::rand() % (10 + 1));
std::this_thread::sleep_for(std::chrono::seconds(seconds_delay));
is_complete = true ;
}
bool has_completed() const { return is_complete; }
};
class request {
private :
std::vector<executor> v_executor;
std::mutex mx;
std::condition_variable cond;
public :
request::request(int exec_cnt) {
for (int i{0}; i<exec_cnt; i++)
v_executor.emplace_back(i);
}
void exec_all () {
std::vector<std::future<void >> futures;
for ( auto & e : v_executor )
futures.push_back(std::async([&e] () { e.execute_something(); } ));
for (auto & fut : futures)
fut.get();
}
bool is_at_least_one_complete() {
std::unique_lock<std::mutex> lk(mx);
cond.wait(lk, [](){ return ;} );
}
};
int main() {
request rq{3};
return 0;
}
As you can see I've create a condition variable, but not sure how to use it in this context or even if I in fact need one?
Any suggestions would be appreciated??
Last edited on Aug 25, 2017 at 2:21pm UTC
Aug 25, 2017 at 3:56pm UTC
With a std::future
, you can call the member function wait_for
with a timeout of zero seconds, and if the return from the function call is future_status::ready
, it's finished.
Aug 25, 2017 at 4:38pm UTC
I cannot have a timeout though, since the length of time is arbitrary and there is no time limit as such.
Aug 25, 2017 at 7:19pm UTC
I don't follow. You asked:
How can I find out if at least one of the executors has completed?
You can find out if at least one of the executors has completed by calling each future's
wait_for
function with a timeout of zero. If any one future says
future_status::ready
, then it has completed.
Aug 25, 2017 at 10:23pm UTC
I never realised that a timeout of zero enables one to check if a std::future has finished or not.
I'm still not 100% sure though how I can obtain the first executor without doing some kind of loop until one of the futures is ready?
Is this code something like you had in mind?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#include <chrono>
#include <iostream>
#include <vector>
#include <thread>
#include <future>
#include <cstdlib>
class executor {
private :
bool is_complete {false };
int exec_id ;
public :
executor(int eid) : exec_id{eid} { }
void execute_something() {
std::srand(std::time(0));
int seconds_delay = (std::rand() % (10 + 1));
std::this_thread::sleep_for(std::chrono::seconds(seconds_delay));
is_complete = true ;
}
bool has_completed() const { return is_complete; }
};
class request {
private :
std::vector<executor> v_executor;
public :
request::request(int exec_cnt) {
for (int i{0}; i<exec_cnt; i++)
v_executor.emplace_back(i);
}
void exec_all () {
std::vector<std::future<void >> futures;
for ( auto & e : v_executor ) {
futures.push_back(std::async([&e] () { e.execute_something(); } ))
}
/* But what if none of them are ready when looping */
for (auto & fut : futures)
fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
for (auto & fut : futures)
fut.get();
}
};
int main() {
request rq{3};
return 0;
}
I've also created the following solution, which seems to work, and uses a kind of callback:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
#include <memory>
#include <chrono>
#include <iostream>
#include <vector>
#include <thread>
#include <future>
#include <cstdlib>
class executor;
class request;
class executor {
int exec_id ;
request& req;
bool is_complete {false };
public :
executor(int eid, request& request_);
void execute_something() ;
bool has_completed() const { return is_complete; }
};
class request {
private :
bool first_done{false };
std::vector<executor> v_executor;
std::mutex mx;
public :
request(int exec_cnt) {
for (int i{0}; i<exec_cnt; i++)
v_executor.emplace_back(i, *this );
}
void communicate_to_client (int exec_id) {
std::lock_guard<std::mutex> lk(mx);
if (!first_done) {
first_done = true ;
std::cout << "Ready - " << exec_id << std::endl;
}
}
void exec_all () {
std::vector<std::future<void >> futures;
for ( auto & e : v_executor )
futures.push_back(std::async([&e] () { e.execute_something(); } ));
for (auto & fut : futures)
fut.get();
}
};
executor::executor(int eid, request& request_) : exec_id{eid}, req{request_} { }
void executor::execute_something() {
std::srand(std::time(0));
int seconds_delay = (std::rand() % (3 + 1));
std::this_thread::sleep_for(std::chrono::seconds(seconds_delay));
is_complete = true ;
req.communicate_to_client(exec_id);
}
int main() {
request rq{3};
rq.exec_all();
return 0;
}
I don't have a solution which uses std::future::ready and std::future_status, but the second code block works.
How can I implement something like the second code block using std::future::ready and std::future_status without doing a while loop?
Last edited on Aug 25, 2017 at 10:24pm UTC
Topic archived. No new replies allowed.