C++: splitting a sum across std::async tasks
Run two halves of a computation concurrently and combine the results with futures.
On this page
C++ vectors, algorithms, and lambdas.
- Run two halves of a computation concurrently and combine the results with futures.
- Predict the sample output and explain the state changes.
- Complete the practice task and check the boundary cases.
The concept
Data parallelism divides a large data set into independent parts that are processed at the same time. std::async launches a function and returns a std::future, a handle for the eventual result. Calling get waits for the task and returns its value or rethrows its exception.
std::launch::async asks for the task to run on a separate thread. Without that flag the implementation may defer the task and run it in get. The two halves read the same vector but write nothing shared, so no locking is needed. std::cref passes the vector by const reference instead of copying it.
Code example
#include <functional>
#include <future>
#include <iostream>
#include <numeric>
#include <vector>
long long sum_range(const std::vector<int>& v, std::size_t from, std::size_t to) {
return std::accumulate(v.begin() + from, v.begin() + to, 0LL);
}
int main() {
std::vector<int> data(1000);
std::iota(data.begin(), data.end(), 1);
auto first = std::async(std::launch::async, sum_range, std::cref(data), 0, 500);
auto second = std::async(std::launch::async, sum_range, std::cref(data), 500, 1000);
long long total = first.get() + second.get();
std::cout << "sum 1..1000 = " << total << "\n";
}sum 1..1000 = 500500
Follow the code
Open the walkthrough to inspect the example one step at a time.
Show guided walkthrough
#include <functional>#include <future>#include <iostream>#include <numeric>#include <vector> long long sum_range(const std::vector<int>& v, std::size_t from, std::size_t to) { return std::accumulate(v.begin() + from, v.begin() + to, 0LL);} int main() { std::vector<int> data(1000); std::iota(data.begin(), data.end(), 1); auto first = std::async(std::launch::async, sum_range, std::cref(data), 0, 500); auto second = std::async(std::launch::async, sum_range, std::cref(data), 500, 1000); long long total = first.get() + second.get(); std::cout << "sum 1..1000 = " << total << "\n";}Follow the example
Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.
View the complete dry-run table
| Step / line | What happens | State after step | Output so far |
|---|---|---|---|
| Fill the vector with 1, 2, ..., 1000. | data = 1..1000 | — | |
| Start the first half on its own thread. | first sums 1..500 = 125250 | — | |
| Start the second half at the same time. | second sums 501..1000 = 375250 | — | |
| Wait for both and add the partial sums: 125250 + 375250. | total = 500500 | — | |
| The answer equals n(n+1)/2. | total = 500500 | sum 1..1000 = 500500 |
Behind the scenes
How C++ processes this code
The C++ compiler produces a native executable. Execution enters main, where objects and function calls perform the work.
Cost and common mistakes
O(n) total work; ideal wall-clock time O(n / p) on p cores.
- A future returned by std::async blocks in its destructor if never fetched, which can silently serialize your tasks.
- For tiny tasks, thread-creation overhead is larger than the work. Parallelism pays off only for enough work per task.
- Never write to shared data from several tasks without a mutex or atomics.
Try it yourself
How would you split the work into four parts?
Reveal answer and reasoning
Launch four async tasks over ranges 0–250, 250–500, 500–750, and 750–1000, then add the four get() results.