In C#, there is async and await that allows you to write asynchronous code easily e.g. doing some calculations while fetching some data from I/O. Asynchronous code improves the responsiveness and is considered an handy way to write multithreading application.
In C++ 11, writing the asynchronous code becomes straightforward. See below the example that sums a ‘large’ array by recursively dividing into two halves (two threads).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | // parallel_sum.cpp // https://helloacm.com/how-to-async-and-await-in-c11/ #include <iostream> #include <vector> #include <future> // for use of std::accumulate #if _MSC_VER #include <numeric> // in Visual Studio #else #include <algorithm> // g++ -std=c++14 -pthread parallel_sum.cpp #endif using namespace std; // generic template <typename TYPE> int parallel_sum(TYPE beg, TYPE end) { // block size auto len = end - beg; if (len < 500) { // if block is small enough, it is faster to just sum them up. return std::accumulate(beg, end, 0); } // (beg + end) / 2 may overflow auto mid = beg + len / 2; // sum the left part asynchronously auto handle_left = std::async(launch::async, parallel_sum<TYPE>, beg, mid); // sum the right part asynchronously auto handle_right = std::async(launch::async, parallel_sum<TYPE>, mid, end); // put them together return handle_left.get() + handle_right.get(); } int main() { vector<int> v(10000, 1); cout << "Sum: " << parallel_sum(v.begin(), v.end()) << endl; } |
// parallel_sum.cpp // https://helloacm.com/how-to-async-and-await-in-c11/ #include <iostream> #include <vector> #include <future> // for use of std::accumulate #if _MSC_VER #include <numeric> // in Visual Studio #else #include <algorithm> // g++ -std=c++14 -pthread parallel_sum.cpp #endif using namespace std; // generic template <typename TYPE> int parallel_sum(TYPE beg, TYPE end) { // block size auto len = end - beg; if (len < 500) { // if block is small enough, it is faster to just sum them up. return std::accumulate(beg, end, 0); } // (beg + end) / 2 may overflow auto mid = beg + len / 2; // sum the left part asynchronously auto handle_left = std::async(launch::async, parallel_sum<TYPE>, beg, mid); // sum the right part asynchronously auto handle_right = std::async(launch::async, parallel_sum<TYPE>, mid, end); // put them together return handle_left.get() + handle_right.get(); } int main() { vector<int> v(10000, 1); cout << "Sum: " << parallel_sum(v.begin(), v.end()) << endl; }
In order to compile it in Linux using gcc compiler, you need to include the support of pthread and use the syntax of C++11, i.e.
1 | g++ -std=c++14 -pthread parallel_sum.cpp |
g++ -std=c++14 -pthread parallel_sum.cpp
The .get() method is the ‘await’ operation but you obviously don’t need the ‘async’ keyword. When the partition size is small enough, it is generally considered more efficient to sum the elements locally using a for loop (CPU benefits from the local cache lines e.g. more cache hits) or in this case the std::accumulate.
The keyword launch::async specifies that a new thread must be created to invoke the function. The std::async then takes the function name and its parameters (variable length of parameters).
Multithreading code is a great hint for the OS to utilize all resources e.g. cores.
–EOF (The Ultimate Computing & Technology Blog) —
Last Post: Multi-Processes Experiments - When Can Windows Utilize All the Cores?
Next Post: How to Make Ping Tests to Global Servers using PHP?