5.2.24 · D1C++ Programming

Foundations — Concurrency — std - thread, std - mutex, std - lock_guard, std - unique_lock

1,743 words8 min readBack to topic

Before you can read the parent note, you need to see what each word and symbol means. We build them one at a time, bottom to top. Nothing below uses a term that was not drawn first.


0. What is a program actually doing? (the "thread" picture)

The picture: a to-do list with a finger pointing at the current line.

Figure — Concurrency — std - thread, std - mutex, std - lock_guard, std - unique_lock

Look at the figure: the left column is one thread (one finger), the right adds a second finger moving independently. Both can read and write the same boxes of memory — that is where trouble begins.


1. Core (CPU) — where a finger actually runs

Why the topic mentions this: the parent says concurrency exists because cores sit idle. One finger uses one core; the other cores do nothing. A second thread puts a second core to work → more steps done per second (throughput).


2. Shared memory — the boxes both fingers touch

Shared memory means: the same box is visible to both fingers. This is powerful (cooperation) and dangerous (collision), which motivates the next section.


3. The read–modify–write picture (why ++counter is really THREE steps)

The parent claims ++counter is not one action but three. Here is the picture that proves it.

Figure — Concurrency — std - thread, std - mutex, std - lock_guard, std - unique_lock

4. Data race — the disease, drawn

Recall Why "at least one writes"?

Two fingers only reading the same box never conflict — reading doesn't change it. The danger is a write happening while another finger reads or writes. ::: Because a write changes the box mid-way, so what the other finger sees depends on luck (timing).

Link: this is exactly Undefined behavior in C++ — the compiler assumes it never happens, so the observed result can be nonsense, not just "sometimes wrong".


5. Serialize — the cure in one word

The whole point of a mutex (next) is to make a chosen region serialized.


6. Mutex — the single key

Figure — Concurrency — std - thread, std - mutex, std - lock_guard, std - unique_lock

In the figure the key forces the two fingers into a queue: finger A holds the key and does its full read-modify-write; finger B is stuck at the door until A returns the key. The race is gone.


7. Scope, construction, destruction — the machinery RAII rides on

Before lock_guard can make sense, you must see scope.

This guaranteed-cleanup rule is the whole foundation of RAII and resource management — "grab the resource in the constructor, release it in the destructor".


8. lock_guard & unique_lock — RAII wrapped around the key


9. The angle-bracket and :: notation you'll keep seeing


Prerequisite map

Program counter = a moving finger

Thread = one finger

Core = one worker

Variable = a box in memory

Shared memory

Read modify write = 3 steps

Data race = lost step

Undefined behavior

Mutex = single key

Block = park and wait

Scope and destructor = guaranteed cleanup

RAII

lock_guard and unique_lock

Safe concurrency

Each row feeds the one below it. By the time you reach lock_guard, every earlier word already has a picture.


Equipment checklist

Test yourself — you are ready for the parent note when you can answer each without peeking.

What is a thread, in the finger picture?
One moving finger stepping through a list of instructions; concurrency = two or more fingers at once.
What does one core give you?
The ability to run exactly one finger (thread) truly simultaneously with others.
Why is ++counter three operations, not one?
It is read the box, add one on a scratch pad, write it back — a second finger can slip in between.
Define a data race in three conditions.
Same memory box, at least one writer, no synchronization ordering them — which is undefined behavior in C++.
What does a mutex physically model?
A single key that only one finger may hold; lock() picks it up (blocking if held), unlock() returns it.
What does "block" mean for a thread?
The OS parks the thread doing nothing until the key it waits for becomes free.
Why can a destructor never be skipped?
Crossing the closing brace of a scope always destroys objects made inside — even on early return or exception.
What is the one-line job of lock_guard?
Lock the mutex in its constructor, unlock in its destructor, so the key is always returned on scope exit.
When do you reach for unique_lock instead?
When you need extra buttons — early unlock, deferred lock, move, or a condition variable.
What does std:: before a name mean?
The name lives in the std namespace (drawer) of the standard library; :: reaches into it.