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
66
and arithmetic is performed upon this value inmain()
, and then the other thread later on delivers66
as 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;
}