C++ · Course navigation

C++: splitting a sum across std::async tasks

Run two halves of a computation concurrently and combine the results with futures.

On this page
Before you start

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

C++
#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";
}
Output
sum 1..1000 = 500500

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1#include <functional>
2#include <future>
3#include <iostream>
4#include <numeric>
5#include <vector>
6
7long long sum_range(const std::vector<int>& v, std::size_t from, std::size_t to) {
8 return std::accumulate(v.begin() + from, v.begin() + to, 0LL);
9}
10
11int main() {
12 std::vector<int> data(1000);
13 std::iota(data.begin(), data.end(), 1);
14
15 auto first = std::async(std::launch::async, sum_range, std::cref(data), 0, 500);
16 auto second = std::async(std::launch::async, sum_range, std::cref(data), 500, 1000);
17
18 long long total = first.get() + second.get();
19 std::cout << "sum 1..1000 = " << total << "\n";
20}

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
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput 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.

Further reading