पाठ 20 / 25

Threads, Mutexes and Atomics

Write basic concurrent code with jthread, mutexes, lock guards and atomics.

Doing several things at once safely

Since C++11, the standard library includes concurrency support. std::thread starts a new thread running a function; it must be joined or detached before destruction, or the program terminates. std::jthread (C++20) joins automatically in its destructor and supports cooperative cancellation through a std::stop_token, so prefer it. When threads share data and at least one writes, you need synchronisation, otherwise you have a data race, which is undefined behaviour. std::mutex with std::lock_guard or std::scoped_lock (RAII locks) protects critical sections; std::scoped_lock can lock several mutexes without deadlock. std::atomic<T> provides lock-free operations on simple values such as counters and flags. std::condition_variable lets threads wait for conditions. std::async and std::future run tasks and retrieve results. For parallel algorithms, C++17 added execution policies (std::execution::par) to many standard algorithms. Keep shared mutable state minimal; passing messages or giving each thread its own data avoids most bugs.

Counting safely from several threads

Atomic counter, mutex-protected vector and automatically joined threads.

#include <atomic>
#include <mutex>
#include <thread>
#include <vector>

int main() {
    std::atomic<long long> hits{0};
    std::vector<int> results;
    std::mutex results_mutex;

    {
        std::vector<std::jthread> workers;
        for (int t = 0; t < 4; ++t) {
            workers.emplace_back([&, t] {
                for (int i = 0; i < 100'000; ++i) {
                    hits.fetch_add(1, std::memory_order_relaxed);   // atomic: no data race
                }
                std::scoped_lock lock(results_mutex);              // RAII lock
                results.push_back(t);
            });
        }
    }   // jthreads join automatically here

    // hits == 400'000 and results holds 4 entries
}

A shared whiteboard with a marker

A mutex is the single marker for a shared whiteboard: only the person holding it may write. An atomic counter is a tally clicker that everyone can press without clashing. Without either, people overwrite each other's work.

त्वरित जाँच: What happens if two threads modify the same int without synchronisation?

  • The result is always correct
  • The compiler adds a lock automatically
  • One thread is blocked automatically
  • It is a data race, which is undefined behaviour
Answer

It is a data race, which is undefined behaviour — Unsynchronised concurrent writes (or a write with a read) are data races and undefined behaviour.