CodeBlanks Logo Icon CodeBlanks

Concurrency

Write parallel processing with std::thread and atomic.

Concurrency layer

In this lesson we add the parallel_sum method to Framework. This method starts a thread with std::thread and sums without data races using std::atomic.

Example: std::atomic<int> total{0}; std::thread t1([&]() { for (auto x : data) if (x > 0) total += x; }); t1.join();. std::atomic makes total += x atomic; this way multiple threads can safely write to the same variable. With join() we wait for the thread to finish. This brings parallel computation into our template. The previous lesson's process_data method stays in place.

Safe access with std::atomic

If multiple threads write to the same variable, a data race occurs and the behaviour is undefined. std::atomic solves this: each read/write becomes atomic.

Example: std::atomic<int> total{0};. total += x; is an atomic read-modify-write operation. When the thread is awaited with join(), the final value of total can be safely read. With return total; the atomic<int> is implicitly converted to int. This is the basis of lock-free parallel summation.

Practice Add the parallel_sum method

Add int parallel_sum(const std::vector<int>& data) to Framework. Body: std::atomic<int> total{0};, std::thread t1([&]() { for (auto x : data) if (x > 0) total += x; });, t1.join();, return total;. In run add std::cout << "parallel: " << parallel_sum(data); (also add << std::endl to the previous line).

Starter code

main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <ranges>
#include <algorithm>
#include <concepts>
#include <thread>
#include <atomic>

class Framework {
public:
    int run();
    template<std::integral T>
    int process_data(const std::vector<T>& data);
    // Add the parallel_sum method (thread + atomic)
};

template<std::integral T>
int Framework::process_data(const std::vector<T>& data) {
    int sum = 0;
    for (auto x : data | std::views::filter([](T v) { return v > 0; })) {
        sum += x;
    }
    return sum;
}

int Framework::run() {
    std::cout << "Project ready" << std::endl;
    std::vector<int> data{1, -2, 3};
    std::cout << "sum: " << process_data(data) << std::endl;
    // Call parallel_sum and print the result
    return 0;
}

int main() {
    Framework fw;
    fw.run();
    return 0;
}

Sample solution

main.cpp
#include <iostream>
#include <string>
#include <vector>
#include <ranges>
#include <algorithm>
#include <concepts>
#include <thread>
#include <atomic>

class Framework {
public:
    int run();
    template<std::integral T>
    int process_data(const std::vector<T>& data);
    int parallel_sum(const std::vector<int>& data);
};

template<std::integral T>
int Framework::process_data(const std::vector<T>& data) {
    int sum = 0;
    for (auto x : data | std::views::filter([](T v) { return v > 0; })) {
        sum += x;
    }
    return sum;
}

int Framework::parallel_sum(const std::vector<int>& data) {
    std::atomic<int> total{0};
    std::thread t1([&]() { for (auto x : data) if (x > 0) total += x; });
    t1.join();
    return total;
}

int Framework::run() {
    std::cout << "Project ready" << std::endl;
    std::vector<int> data{1, -2, 3};
    std::cout << "sum: " << process_data(data) << std::endl;
    std::cout << "parallel: " << parallel_sum(data);
    return 0;
}

int main() {
    Framework fw;
    fw.run();
    return 0;
}

Expected output

Project ready
sum: 4
parallel: 4

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 std::thread

Question
std::____ t1([&]() { total += 1; });
Answer
std::thread t1([&]() { total += 1; });

Explanation: std::thread starts a thread.

2 What does std::atomic provide?

  • Access to a shared variable without data races Correct answer
  • Memory savings
  • Less code
  • Faster summation

Explanation: std::atomic provides access to a shared variable without data races.

3 Match each member to its role

Term Meaning
std::thread Thread
std::atomic Data race protection
join() Waiting
lambda Worker body

All lessons in Advanced