Hello everyone! Today we’re going to talk about std::future
and std::promise
in C++. With the rise of multi-core processors, asynchronous programming has become an important skill for developers to master. The std::future
and std::promise
introduced in the C++11 standard are great partners for handling asynchronous tasks, allowing us to complete asynchronous operations more elegantly.
In this article, I will explain the basic concepts of std::future
and std::promise
and their practical applications in asynchronous tasks using simple and understandable language. We will demonstrate step by step how they work together through code examples. Are you ready? Let’s get started!
1. What are std::future
and std::promise
?
1. std::future
std::future
is an object used to obtain the result of an asynchronous operation. It can be understood as a placeholder for a “future value” that allows you to retrieve the result of a task at the appropriate time.
For example, if you send a thread to run, and you sit in a chair waiting for it to finish and tell you the result, that “result” is std::future
.
2. std::promise
std::promise
is an object used to set the “future value”. It is responsible for passing the result to the associated std::future
.
Continuing with the previous analogy, the runner is std::promise
, and he will eventually provide a “run completed” result to let you (std::future
) know.
The Relationship Between Them
std::promise
and std::future
are good partners:
-
std::promise
sets the value. -
std::future
gets the value.
Their working mechanism is as follows:
-
You create a std::promise
object. -
You obtain an associated std::future
object through thestd::promise::get_future()
method. -
In another thread, std::promise
sets the value, andstd::future
is responsible for asynchronously obtaining this value.
2. Code Example: Basic Usage of std::future
and std::promise
Let’s look at a simple example to see how they work.
Example: Calculating the Square of a Number
#include <iostream>
#include <thread>
#include <future> // Include std::future and std::promise
// Asynchronous task: calculate square
void calculateSquare(std::promise<int> promise, int value) {
int result = value * value;
std::this_thread::sleep_for(std::chrono::seconds(2)); // Simulate time-consuming operation
promise.set_value(result); // Set the calculated result in promise
}
int main() {
std::promise<int> promise; // Create promise
std::future<int> future = promise.get_future(); // Get the associated future with promise
int value = 5;
std::thread t(calculateSquare, std::move(promise), value); // Start thread, passing promise
std::cout << "Calculating the square of " << value << "..." << std::endl;
int result = future.get(); // Get the result of the asynchronous operation (blocking wait)
std::cout << "Result is: " << result << std::endl;
t.join(); // Wait for thread to finish
return 0;
}
Output Result
Calculating the square of 5...
Result is: 25
Code Interpretation
-
**Create std::promise
**:std::promise<int> promise
is used to store the calculation result. -
**Get std::future
**: Get the associatedfuture
object throughpromise.get_future()
. -
Asynchronous Task: In the asynchronous thread, call promise.set_value()
to set the result. -
Synchronous Result Retrieval: The main thread retrieves the asynchronous result through future.get()
. This call is blocking until the asynchronous task completes.
3. std::async
: Simplifying Asynchronous Operations
C++ provides a simpler tool—**std::async
**, which can automatically create threads for us and return a std::future
object. This way, we do not need to manually create std::promise
and threads.
Example: Using std::async
to Calculate Square
#include <iostream>
#include <future> // Include std::async and std::future
// Asynchronous task: calculate square
int calculateSquare(int value) {
std::this_thread::sleep_for(std::chrono::seconds(2)); // Simulate time-consuming operation
return value * value;
}
int main() {
int value = 5;
// Use std::async to start asynchronous task
std::future<int> future = std::async(std::launch::async, calculateSquare, value);
std::cout << "Calculating the square of " << value << "..." << std::endl;
int result = future.get(); // Get the result of the asynchronous operation (blocking wait)
std::cout << "Result is: " << result << std::endl;
return 0;
}
Output Result
Calculating the square of 5...
Result is: 25
Advantages of std::async
-
Simplified Code: No need to manually create std::promise
and threads. -
Convenient and Flexible: Directly returns std::future
, allowing us to easily obtain results.
4. Common Methods of std::future
std::future
provides some convenient methods to handle asynchronous results:
-
get()
blocks waiting for the asynchronous task to complete and returns the result. -
wait()
blocks waiting for the task to complete but does not return the result. -
wait_for()
waits for a specified time, returning a timeout status if it exceeds the time limit.
Example: Using wait_for
#include <iostream>
#include <future>
#include <chrono>
int main() {
// Asynchronous task
std::future<int> future = std::async(std::launch::async, [] {
std::this_thread::sleep_for(std::chrono::seconds(2));
return 42;
});
std::cout << "Waiting for task to complete..." << std::endl;
// Wait for up to 1 second
if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout) {
std::cout << "Task timed out!" << std::endl;
} else {
std::cout << "Task completed, result is: " << future.get() << std::endl;
}
return 0;
}
Output Result
Waiting for task to complete...
Task timed out!
5. Precautions and Tips
-
future.get()
is a one-time operation: After callingget()
, the result offuture
is taken away, and calling it again will throw an exception. -
Avoid Deadlocks: When using std::promise
andstd::future
, ensure that threads can finish normally, otherwise it may lead to deadlocks. -
Delay Start of std::async
: By default,std::async
may delay the execution of tasks. You can force immediate start by usingstd::launch::async
.
6. Exercises
-
Modify the first example code to calculate the sum of two numbers in the thread and return the result to the main thread. -
Use std::async
to implement a program that simulates the time-consuming operation of downloading a file. -
Use std::future::wait_for
to check if a task has timed out and return a default value in case of timeout.
Conclusion
Through this article, we learned about std::future
and std::promise
in C++, understood how they work together to achieve asynchronous operations, and saw how std::async
simplifies the writing of asynchronous tasks. Mastering these tools will allow you to handle asynchronous tasks more confidently in multithreaded programming.
That’s all for today’s C++ learning journey! Remember to try the code, and feel free to ask me any questions in the comments section. I wish you all success in your learning, and may your C++ skills improve continuously! See you next time! 😊