C++ by Example
C++ by Example

Threads

1 min read

Threads

C++11 added native threading support through <thread>, <mutex>, and related headers. Threads let multiple parts of a program run concurrently, making better use of multi-core hardware.

Creating a thread

#include <iostream>
#include <thread>

void worker(int id) {
    std::cout << "Thread " << id << " running\n";
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);

    t1.join();   // wait for t1 to finish
    t2.join();   // wait for t2 to finish

    std::cout << "Both threads done\n";
}

std::thread takes a callable and any arguments to forward to it. Calling join() blocks until the thread finishes. If you destroy a std::thread without calling join() or detach(), std::terminate is called.

Lambdas as thread functions

#include <thread>
#include <iostream>

int main() {
    int result = 0;

    std::thread t([&result]() {
        result = 42;   // capture by reference
    });

    t.join();
    std::cout << result << "\n";   // 42
}

Be careful with captures: the lambda must not outlive the captured variables.

Detaching threads

detach() lets a thread run independently. The thread keeps running after main returns — use carefully:

std::thread t(background_task);
t.detach();   // t is no longer joinable; runs independently

Detached threads are hard to reason about. Prefer join() and structured concurrency.

Hardware concurrency

unsigned int n = std::thread::hardware_concurrency();
std::cout << "CPU cores: " << n << "\n";

Thread IDs

std::cout << "Main thread: " << std::this_thread::get_id() << "\n";

std::thread t([]() {
    std::cout << "Worker thread: " << std::this_thread::get_id() << "\n";
});
t.join();

Sleeping

#include <chrono>

std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::sleep_for(std::chrono::seconds(1));

A parallel sum example

#include <thread>
#include <vector>
#include <numeric>
#include <iostream>

int main() {
    std::vector<int> data(1'000'000, 1);
    long long result1 = 0, result2 = 0;

    auto half = data.size() / 2;

    std::thread t1([&]() {
        result1 = std::accumulate(data.begin(), data.begin() + half, 0LL);
    });
    std::thread t2([&]() {
        result2 = std::accumulate(data.begin() + half, data.end(), 0LL);
    });

    t1.join();
    t2.join();

    std::cout << result1 + result2 << "\n";   // 1000000
}

std::jthread (C++20)

std::jthread is a std::thread that automatically joins on destruction — eliminating the risk of accidental std::terminate:

#include <thread>

int main() {
    std::jthread t([]() {
        std::cout << "running\n";
    });
}   // t joins here automatically — no explicit join needed
C++ by Example
C++ by Example

Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.

View book →