Course contents
On this page
Let two operations overlap without confusing their steps
Separate a request, a thread, and a transaction before examining a race.
So far, our storage examples allowed one operation at a time. A shop usually has several requests in progress: one waits for a file read while another is ready to inspect a cached product. We would like to use the processor while the first waits.
A thread is a sequence of execution within a running process. Threads in one process can access shared memory. A request is a unit of work asked for by a caller. A transaction groups database operations under correctness rules. These are related, but they are not interchangeable counts.
Overlap does not require simultaneous instructions
Concurrency means operations are in progress during overlapping intervals. Parallelism means some of their work executes at the same time, for example on different processor cores. A single core can interleave two threads and expose a race even though it executes only one of their instructions at a time.
Suppose two workers each increment a shared completed-request counter, initially 0. Treat reading, adding, and writing as separate steps.
- Worker A reads 0
It computes its private result, 1, but has not stored it.
- Worker B reads 0
It also computes 1 and stores 1.
- Worker A resumes
It stores its earlier result, 1. Two completions produced a count of one.
A critical section is code that must be coordinated with conflicting access to shared state. A mutex, a lock permitting one holder, can protect the whole read-modify-write operation. Protecting only the final assignment would leave both workers free to read the same earlier value.
This protects one in-memory counter. It does not create database durability or transaction isolation for unrelated rows. Those require their own protocols.
Waiting work still occupies resources
A worker waiting for storage may retain a request, memory, and database state. Adding more threads can overlap useful waits, but it can also increase retained state and competition. An event loop is another organization: resume an operation when its awaited event is ready, rather than reserve a running thread for every idle request.
Either design must bound queued work and release resources after errors or cancellation. A long computation on one event-loop thread can delay other callbacks even when their data is ready.
Protect the right interval
Both workers acquire a mutex only while writing their computed value. They read and add before acquiring it. Is the counter fixed?
Trace the original interleaving again
No. Both can still read 0 and compute 1 before either writes. They then take turns storing 1. The protected interval must cover the dependent read and modification, or use a suitable atomic increment operation that provides that combined behavior.
We can now examine two purchase requests using the same reasoning: identify the shared fact, list the steps, and find which interleavings violate the rule.
OSTEP’s concurrency introduction develops threads and shared-state interleavings.
Extended reference
The extended chapter preserves the original technical coverage, additional examples, and citations. The explanation above supplies the concepts needed for this page; the reference develops the specialist cases.
Find a section from the original chapter
- Learning outcomes
- Many clients, few execution resources
- The lifecycle of a request
- Processes and threads
- Scheduling and context switching
- Event loops and asynchronous state machines
- Synchronization and critical sections
- Ownership can replace some synchronization
- Little’s Law connects concurrency to latency
- Fairness and long operations
- Case connection: fast command execution and slow neighbors
- Follow an asynchronous read without assuming free execution
- A bounded scheduling state machine
- The difference between a pool and a pipeline
- Why more threads can reduce useful throughput
- Scenario: a transaction waits while retaining the wrong thing
- Visualize execution and waiting on different lanes
- Design conclusion
- Sources and further reading