CS 452/652 Spring 2026 - Lecture 21
Multi-Core Programming / Overview
July 27, 2026 prev next
Parallelism
- multiple independent execution streams
- unknown and non-deterministic execution progress
- similar to asynchronous interrupt handling
Atomicity
Init: A = 0
Thread 1 Thread 2
A += 1 A += 1
Result: ?
Critical Section: Dekker's Algorithm (software locking)
- assume atomic assignment
- shared initialization
int wantIn[2] = {false, false};
int turn = 0;
int me = 0; // other thread: me = 1
int you = 1 - me;
wantIn[me] = true;
while (wantIn[you]) {
if (turn != me) {
wantIn[me] = false;
while (turn != me) { // wait }
wantIn[me] = true;
}
}
... // critical section
turn = you;
wantIn[me] = false;
Critical Section: Atomic Operations
- atomic read-modify-write instructions:
- increment, compare-and-swap, load/store transactions
- solves simple shared access
- build critical section lock
- example: ticket lock
- shared initialization
int ticket = 0;
int serving = 0;
int myticket = ticket++;
while (myticket != serving) { // wait }
... // critical section
serving++;
- only
ticket++ must be atomic operation
Blocking vs. Spinning
- the above locking schemes are spin-locks
- threads busy-loop while waiting
- threading runtimes typically also build blocking locks
- use spin-lock to protect scheduler
- performance/efficiency trade-off
Memory Ordering
- compiler respects sequential data dependencies
- each core respects sequential data dependencies
- what about sequential execution without data dependencies?
Init: A = B = 0
Thread 1 Thread 2
A = 1 B = 1
print(B) print(A)
Output: ?
- memory hierarchy & pipeling → out-of-order execution
- write buffers, caching hierarchy
- amplifies parallelism challenge
- think of the effects as operations that "float" around
- example memory model: total-store-order (TSO)
- write can be delayed after read
- write/write not reordered
- does not avoid 00 outcome above
- RISC processors (such as ARM) often implement more relaxed models (more reordering)
- trade-off: programming semantics ↔ performance
Mechanisms
- C 'volatile' avoids compiler reordering and register caching
- atomic instructions: consistency/correctness of parallel operations
- memory barrier/fence: execution ordering
- load/acquire: no later loads started
- store/release: all earlier stores completed
- global ordering of barrier/fence instructions
- Dekker: load/store fence after each
wantIn[me] = true
Sequential Consistency
- one of many consistency models
- formal description effects of parallel operations on mutable state
- formal reasoning about program correctness
- some model more restricted, some more relaxed
- intuitive model: direct shared memory (no buffering)
- writes become globally visible in local per-processor order
- some global interleaving of writes
- printing example above: sequential consistency prohibits 00 outcome
- atomic operation guarantees SC for atomic variables
- memory barrier guarantees SC for critical section data
- need load/acquire fence before and store/release fence after critical section
- example: ticket lock
int myticket = ticket++;
while (myticket != serving) { // wait }
LOAD FENCE
... // critical section
STORE FENCE
serving++;
Additional Notes
- Java 'volatile' essentially means Sequential Consistency
- x86 atomic instructions (
lock prefix) include barrier semantics