Details:
In the program below, multiple threads (in this case only 2 for simplicity) listen out for the same value of 66 to be returned from the functions, following some logic in both functions that produces the result 66.
The threads use async, and the values of 66 are returned using futures. A while loop is used in an attempt to continually check the status of threads one and two to check if either of them have completed, in which case the fastest result from either of the threads is then fetched and used in some calculation.
Goal:
- Out of the two
threads, to detect which one of them is first to return the value of66 - As soon as a thread returns
66(regardless of if the other thread has completed), the returned value is then made available inmain()for some further simple arithmetic to be performed upon it - If a thread returns
66and arithmetic is performed upon this value inmain(), and then the other thread later on delivers66as well, this second returned value should not be used in any calculations
Please note: before deciding to post this question, the following resources have been consulted:
- How to check if thread has finished work in C++11 and above?
- Using Multithreading two threads return same value with different inputs?
- C++ threads for background loading
- Future returned by a function
- Start multiple threads and wait only for one to finish to obtain results
Problems and Current Ouput:
Currently, the program always outputs that the first thread to finish is rf1, even if the code in function1 is substantially slower (e.g. a for loop with 1000 iterations in function1, and a for loop with 10 iterations in function1). This leads me to believe there is some sort of blocking behaviour somewhere that I may have introduced?
Program Attempt:
#include <future>
#include <iostream>
#include "unistd.h"
double function1() {
// Logic to retrieve _value
// ...
double _value = 66;
return _value;
}
double function2() {
// Logic to retrieve _value
// ...
double _value = 66;
return _value;
}
int main() {
double ret_value = 0;
auto rf1 = std::async(std::launch::async, function1);
auto status1 = rf1.wait_for(std::chrono::nanoseconds(1));
auto rf2 = std::async(std::launch::async, function2);
auto status2 = rf2.wait_for(std::chrono::nanoseconds(1));
while (true) {
if (status1 == std::future_status::ready) {
std::cout << "RF1 FINISHED FIRST" << std::endl;
// No longer need returned val from 2nd thread.
// Get result from 1st thread
ret_value = rf1.get();
break;
}
else if (status2 == std::future_status::ready) {
std::cout << "RF2 FINISHED FIRST" << std::endl;
// No longer need returned val from 1st thread.
// Get result from 2nd thread
ret_value = rf2.get();
break;
}
else if (status1 != std::future_status::ready) {
// RF1 not finished yet
status1 = rf1.wait_for(std::chrono::nanoseconds(1));
}
else if (status2 != std::future_status::ready) {
// RF2 not finished yet
status2 = rf2.wait_for(std::chrono::nanoseconds(1));
}
}
// Do some calculations on the quickest
// returned value
double some_value = ret_value + 40;
return 0;
}
Questions:
Q1. Can the program be modified in any way to detect the fastest thread to return so that the returned value of 66 can be used within main() for further calculations?
Q2. Has the while loop introduced any sort of blocking behaviour?
If anyone may be able to advise or point to some resources that could aid in solving this dilemma, it would be greatly appreciated. So far, it has been a challenge to find multithreading documentation that exactly matches this scenario.
EDIT:
Based on a helpful answer from @jxh, the else if conditions instructing the WHILE loop to continue waiting have been removed, as seen further below.
Furthermore, some logic has been added to function1 and function2 to see which one will finish first. As seen in the code, function1 has 98 iterations and function2 has 100 iterations, yet the output continually says that function2 has finished first:
#include <future>
#include <iostream>
#include "unistd.h"
double function1() {
// Logic to retrieve _value
for (int i = 0; i < 98; i++) {
std::cout << std::endl;
}
double _value = 66;
return _value;
}
double function2() {
// Logic to retrieve _value
for (int i = 0; i < 100; i++) {
std::cout << std::endl;
}
double _value = 66;
return _value;
}
int main() {
double ret_value = 0;
auto rf1 = std::async(std::launch::async, function1);
auto status1 = rf1.wait_for(std::chrono::nanoseconds(1));
auto rf2 = std::async(std::launch::async, function2);
auto status2 = rf2.wait_for(std::chrono::nanoseconds(1));
while (true) {
if (status1 == std::future_status::ready) {
std::cout << "RF1 FINISHED FIRST" << std::endl;
// No longer need returned val from 2nd thread.
// Get result from 1st thread
ret_value = rf1.get();
break;
}
else if (status2 == std::future_status::ready) {
std::cout << "RF2 FINISHED FIRST" << std::endl;
// No longer need returned val from 1st thread.
// Get result from 2nd thread
ret_value = rf2.get();
break;
}
status1 = rf1.wait_for(std::chrono::nanoseconds(1));
status2 = rf2.wait_for(std::chrono::nanoseconds(1));
}
// Do some calculations on the quickest
// returned value
double some_value = ret_value + 40;
return 0;
}