I'm new to C threads concept and is trying to comprehend the benefit of the promise/future abstraction. With promise and future, I understand that it allows an async function to "return" like a regular subroutine does. However, it is not clear to me what it offers beyond using referenced argument to do the same thing.
#include <iostream>
#include <thread>
void f(int& x)
{
x = 1;
}
int main()
{
int a = 1;
std::thread t(f, std::ref(a));
t.join();
std::cout << a << '\n';
}
In the above example, I make the function f()
"returns" the integer by passing a reference. This is safe as I only grab the value after thread is join. Now is there any benefit from using promise/future that the above paradigm cannot do?
CodePudding user response:
This is safe as I only grab the value after thread is join
Well, that's kind of the point, isn't it? Is it really "safe" if all it takes for some code to become "unsafe" is for someone to inadvertently use the variable at the wrong time? If the difference between "safe" and "completely broken" is changing the order of two lines, and no compiler can catch the problem, is it really "safe?"
If you invoke an asynchronous action, the primary reason you did that was because you wanted to do something else while that action is going on. So leaving the current stack frame is kind of the point. Most code does not look like your simplistic example.
Your example is only "safe" because it is simplistic. Introduce any complexity, and it becomes increasingly unsafe.
Did the thread raise an exception instead of returning a valid value? Did you make sure that the lifetime of the object being referenced persists until the thread is finished writing to it? If you want the thread to be able to finish with a task and go do a different one (instead of incurring the cost of creating a new std::thread
every time you want to do an async process), how do you communicate when the value is ready to the outside world?
promise
/future
has answers to all of these questions. It has an explicit mechanism for sheparding exceptions across threads. The lifetime of the shepherded object is rigidly controlled, so that simply can't break. Each promise
/future
is independent and thus a thread could have many of them, and any future
can tell when the promise
d value is ready. Etc.
In summary, promise
/future
are tools that are safe at scale. Yours is increasingly less safe the more complexity is introduced.