c++11 Multithreaded programming std::async introduction and examples
- 2020-11-26 18:56:57
- OfStack
This section discusses how std::async is used in C++11 to perform asynchronous task.
C++11 introduced std::async
What is a std: : async
std::async() is a function template that takes callbacks (functions or function objects) as arguments and may execute them asynchronously.
template<class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);
std::async returns 1 std::future < T > , which stores the value returned by the function object executed by std::async().
The expected arguments of the function can be passed to std::async() as arguments following the function pointer argument.
The first parameter in std::async is the startup policy, which controls the asynchronous behavior of std::async. We can create std::async using three different startup policies
std: : launch: : async
Asynchronous behavior is guaranteed, that is, the transfer function will execute in a separate thread
std: : launch: : deferred
Non-asynchronous behavior is invoked when another thread calls get() to access the Shared state
std: : launch: : async | std: : launch: : deferred
Default behavior. With this startup policy, it can run asynchronously or not, depending on the load on the system, but we have no control over it.
If we do not specify a boot policy, it will behave like std::launch::async | std::launch::deferred
In this section we will use the std::launch::async startup strategy
We can pass any callback on std::async, such as:
· Function pointer
· Function objects
· lambda expression
std: : async demand
Suppose we have to get some data (strings) from the database and the file system, and then we need to merge the strings and print them.
In a single thread, we do this:
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
using namespace std::chrono;
std::string fetchDataFromDB(std::string recvData) {
// Make sure that the function is 5 Seconds to complete
std::this_thread::sleep_for(seconds(5));
// Handle creating a database connection, fetching data, and so on
return "DB_" + recvData;
}
std::string fetchDataFromFile(std::string recvData) {
// Make sure that the function is 5 Seconds to complete
std::this_thread::sleep_for(seconds(5));
// Process the fetch file data
return "File_" + recvData;
}
int main() {
// Get start time
system_clock::time_point start = system_clock::now();
// Get data from the database
std::string dbData = fetchDataFromDB("Data");
// Get data from a file
std::string fileData = fetchDataFromFile("Data");
// Get end time
auto end = system_clock::now();
auto diff = duration_cast<std::chrono::seconds>(end - start).count();
std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
// The assembly data
std::string data = dbData + " :: " + fileData;
// Output the assembled data
std::cout << "Data = " << data << std::endl;
return 0;
}
Output:
[
Total Time Taken = 10 Seconds
Data = DB_Data :: File_Data
Since the functions fetchDataFromDB() and fetchDataFromFile() run for 5 seconds each in a separate thread, the total time is 10 seconds.
Since retrieving data from the database and file system is independent and time consuming, we can run them in parallel.
One way is to create a new thread and pass one promise as an argument to the thread function and get data from the associated std::future object in the calling thread
Another way is to use std::async
Use the function pointer to call std::async as a callback
Modify the code above and call fetchDataFromDB() asynchronously using std::async
std::future<std::string>resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
std::string dbData = resultDromDB.get()
std::async() does the following
· Automatically create 1 thread (or pick from the internal thread pool) and 1 promise object.
· The std::promise object is then passed to the thread function and the associated std::future object is returned
· When the function we passed the parameter exits, its value will be set in the promise object, so the final return value will be available in the std::future object
Now change the above example and use std::async to asynchronously fetch data from the database
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <future>
using namespace std::chrono;
std::string fetchDataFromDB(std::string recvData) {
// Make sure that the function is 5 Seconds to complete
std::this_thread::sleep_for(seconds(5));
// Handle creating a database connection, fetching data, and so on
return "DB_" + recvData;
}
std::string fetchDataFromFile(std::string recvData) {
// Make sure that the function is 5 Seconds to complete
std::this_thread::sleep_for(seconds(5));
// Process the fetch file data
return "File_" + recvData;
}
int main() {
// Get start time
system_clock::time_point start = system_clock::now();
std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
// Get data from a file
std::string fileData = fetchDataFromFile("Data");
// from DB To get the data
// The data in future<std::string> Object before it can be retrieved 1 The straight block
std::string dbData = resultFromDB.get();
// Get end time
auto end = system_clock::now();
auto diff = duration_cast<std::chrono::seconds>(end - start).count();
std::cout << "Total Time taken= " << diff << "Seconds" << std::endl;
// The assembly data
std::string data = dbData + " :: " + fileData;
// Output the assembled data
std::cout << "Data = " << data << std::endl;
return 0;
}
Output:
[
Total Time taken= 5Seconds
Data = DB_Data :: File_Data
It only took 5 seconds
Call std::async with the Function object as a callback
/*
* Function Object
*/
struct DataFetcher {
std::string operator ()(std::string recvdData) {
// Make sure that the function is 5 Seconds to complete
std::this_thread::sleep_for(seconds(5));
// Process the fetch file data
return "File_" + recvdData;
}
};
// Call with a function object std::async
std::future<std::string> fileResult = std::async(DataFetcher(), "Data");
Use the lambda function as a callback to call std::async
std::future<std::string> resultFromDB = std::async([](std::string recvdData) {
std::this_thread::sleep_for(seconds(5));
// Handle creating a database connection, fetching data, and so on
return "DB_" + recvdData;
}, "Data");
conclusion