4.3 Software Solutions: Lock Variable, Strict Alternation & Peterson's Algorithm
π‘ Core Intuitionβ
π³ The Everyday Analogy: The Shared Office Whiteboard & Polite Post-it Noteβ
Imagine two software engineers, Alice () and Bob (), sharing a single whiteboard (the Critical Section):
The Shared Whiteboard Politeness Protocol
Mapping progressive software synchronization attempts to real-world peer coordination
Strict Alternation Token
Alice must use it, then Bob must use it, in rigid alternating sequence.
I Want To Write Sticky Notes
Each engineer posts a sticky note before stepping up to the board.
Polite Deference Token
I declare intent, but politely grant first turn to you.
- Strict Turn: High fairness, but zero flexibility (Progress fails).
- Intent Flags: Shows active interest, but simultaneous claims cause a standoff (Deadlock occurs).
- Peterson's Insight: Declare your intent, but set the turn token to the other person. Whoever yields last yields gracefully without deadlock.
π» Bridging to Computer Scienceβ
In operating systems, computer scientists historically sought pure software-based solutions to the 2-process critical section problem without relying on specialized hardware instructions. This evolutionary path progresses through four distinct algorithms:
- The Lock Variable Solution (Naive, Flawed)
- The Turn Variable Solution / Strict Alternation (Flawed Progress)
- The Flag Variable Solution (Deadlock Hazard)
- Peterson's Algorithm (Complete, Provably Correct)
π Core Deep-Dive & Conceptsβ
1. Evolutionary Comparison of Software Solutionsβ
The 4 Software Synchronization Solutions Evolution
Tracing the progression from naive attempts to mathematically verified algorithms
1. Lock Variable
Completely Flawed- Mechanism: Single shared boolean variable lock initialized to 0.
- Fatal Flaw: Preemption between reading lock == 0 and writing lock = 1.
- Verdict: VIOLATES Mutual Exclusion. Completely invalid.
2. Turn Variable
Strict Alternation- Mechanism: Shared turn variable alternately set to 0 and 1.
- Strengths: Follows Mutual Exclusion perfectly.
- Fatal Flaw: VIOLATES Progress due to rigid alternating coupling.
3. Flag Array
Intent Signaling- Mechanism: Boolean array flag[2] signaling active intent to enter.
- Strengths: Follows Mutual Exclusion.
- Fatal Flaw: VIOLATES Progress due to permanent Deadlock when flags overlap.
4. Peterson's Algorithm
Provably Correct- Mechanism: Combines both flag array (intent) and turn variable (politeness).
- Mutual Exclusion: Satisfied 100%.
- Progress & Bounded Waiting: Satisfied 100%.
2. Solution 1: Turn Variable (Strict Alternation)β
Definition: In the Turn Variable solution, a shared Boolean variable
turnis initialized to or . Each process spins untilturnmatches its own process ID, executes its Critical Section, and transfersturnto its peer.
// Shared variable: boolean turn (initially 0 or 1)
// Process P0 // Process P1
void P0() { void P1() {
while (1) { while (1) {
while (turn != 0); // Spin while (turn != 1); // Spin
/* Critical Section */ /* Critical Section */
turn = 1; turn = 0;
/* Remainder Section */ /* Remainder Section */
} }
} }
Turn Variable: Criteria Compliance Analysis
Evaluating why strict alternation guarantees mutual exclusion but destroys progress
Mutual Exclusion: PASSED
- β’turn can only hold ONE scalar value at any instant (0 or 1).
- β’P0 enters if and only if turn == 0.
- β’P1 enters if and only if turn == 1.
- β’Both processes can never enter the Critical Section simultaneously.
Progress: FAILED
- β’Forced Alternation: P0 cannot enter twice in a row without P1 executing.
- β’Remainder Section Lockout: If P1 terminates or idles in its remainder section, turn remains 1 forever.
- β’Zero Intent Inquiry: We never ask the process whether it actually wishes to enter the CS or not.
3. Solution 2: Flag Variable (Intent Array)β
To avoid forcing uninterested processes to take turns, we introduce an explicit intent array:
// Shared variable: boolean flag[2] = {false, false};
// Process P0 // Process P1
void P0() { void P1() {
while (1) { while (1) {
flag[0] = true; flag[1] = true;
while (flag[1]); // Wait while (flag[0]); // Wait
/* Critical Section */ /* Critical Section */
flag[0] = false; flag[1] = false;
/* Remainder Section */ /* Remainder Section */
} }
} }
Why the Flag Solution Dies in Deadlock:β
- Suppose both processes wish to enter simultaneously.
- executes
flag[0] = true; - A timer interrupt occurs. executes
flag[1] = true; - Now, both flags are
true(flag[0] == trueandflag[1] == true). - enters its while-loop:
while(flag[1])spins becauseflag[1]is true. - enters its while-loop:
while(flag[0])spins becauseflag[0]is true. - Neither process ever resets its flag, and neither ever enters the Critical Section.
- Result: Deadlock occurs! In attempting to achieve progress, the system ends up frozen.
4. Solution 3: Peterson's Algorithm (The Unified Masterpiece)β
Definition: Peterson's Algorithm is a classic software-based solution to the critical section problem for two processes. It combines both the intent flag array and the turn variable.
// Shared variables:
boolean flag[2] = {false, false};
int turn = 0; // or 1
// Process P0 (i = 0, j = 1) // Process P1 (i = 1, j = 0)
void P0() { void P1() {
while (1) { while (1) {
flag[0] = true; flag[1] = true;
turn = 1; turn = 0;
while (flag[1] && turn == 1); while (flag[0] && turn == 0);
/* === CRITICAL SECTION === */ /* === CRITICAL SECTION === */
flag[0] = false; flag[1] = false;
/* Remainder Section */ /* Remainder Section */
} }
} }
Step-by-Step Mathematical Correctness Proof:β
1. Proof of Mutual Exclusionβ
For both and to be in their Critical Sections simultaneously, both while-loop exit conditions must evaluate to false at the exact same instant:
- enters only if:
flag[1] == falseORturn == 0 - enters only if:
flag[0] == falseORturn == 1
If both processes are actively competing to enter, both have set their flags to true (flag[0] == true and flag[1] == true).
Therefore, entry depends entirely on turn. But turn is a scalar hardware memory variableβat any physical instant, turn is either or , but never both simultaneously.
- If
turn == 0, enters and spins. - If
turn == 1, enters and spins. - Mutual Exclusion is strictly guaranteed.
2. Proof of Progressβ
- If is in its Remainder Section (
flag[1] == false), setsflag[0] = true; turn = 1;. When evaluateswhile(flag[1] && turn == 1), sinceflag[1]is false, the loop condition fails immediately and enters the Critical Section without waiting. - If both wish to enter at the same instant, both set their flags to
true. Whichever process setsturnlast overwrites the other process's turn assignment, allowing the other process to enter immediately. Zero deadlock occurs. Progress is satisfied.
3. Proof of Bounded Waitingβ
Suppose finishes its Critical Section and immediately wants to re-enter.
Upon exit, sets flag[0] = false.
If attempts to enter again, it sets flag[0] = true and must set turn = 1.
Since has been waiting with flag[1] == true, the fact that overwrote turn with ensures that exits its spin-loop and enters the Critical Section before can enter a second time.
- can cut ahead of waiting at most time.
- Bounded Waiting is strictly satisfied.
π Architecture / Visual Blueprintβ
Peterson's Simultaneous Contention Traceβ
Peterson's Algorithm: Simultaneous Contention Resolution
Tracing how simultaneous entry requests are deterministically resolved by the final turn write
P0 Declares Intent: flag[0] = true
P1 Declares Intent: flag[1] = true
P0 Sets turn = 1
P1 Overwrites turn = 0
P0 Checks: (turn == 1) is FALSE
P1 Spins: (turn == 0 && flag[0]) is TRUE
π In The Real World: Production Case Studyβ
Why Peterson's Algorithm Fails on Modern CPUs (Memory Reordering)β
While mathematically perfect on classical sequentially consistent hardware, Peterson's Algorithm fails catastrophically on modern x86 and ARM processors without memory fences:
// Process P0 Entry Section
flag[0] = true;
turn = 1;
while (flag[1] && turn == 1);
The Hardware Problem: Out-of-Order Executionβ
Modern superscalar processors use Store Buffers and aggressively reorder independent memory operations for performance.
- To the CPU core, writing to
flag[0]and writing toturntarget two completely independent memory addresses. - A modern CPU may reorder the memory writes: committing
turn = 1beforeflag[0] = truearrives at the cache coherency bus. - If both cores reorder their store instructions, both processes can enter the Critical Section simultaneously, violating Mutual Exclusion!
The Production Fix: Memory Barriersβ
In Linux and modern C11/C++20, developers enforce sequential consistency using hardware memory fences:
// Correct production implementation with Memory Barriers
void P0_modern() {
flag[0] = true;
turn = 1;
__atomic_thread_fence(__ATOMIC_SEQ_CST); // Memory barrier (mfence / dmb)
while (flag[1] && turn == 1);
/* Critical Section */
flag[0] = false;
}
π― Exam & Interview Pitfall Checkβ
Question 1: Prove mathematically why Peterson's algorithm satisfies the Mutual Exclusion criterion. Answer:
- In Peterson's algorithm, process can enter its critical section only if:
flag[1] == falseORturn == 0. - Similarly, process enters only if:
flag[0] == falseORturn == 1. - If both processes attempt to enter simultaneously, both set their intent flags to
true(flag[0] == trueandflag[1] == true). - Therefore, entry depends strictly on the value of
turn. - Since
turnis a scalar hardware variable, it can only hold either or at any physical instant. The process for whichturnmatches its own ID will enter, while the other will spin. Simultaneous entry is physically impossible, proving Mutual Exclusion.
Question 2: Why does the Turn Variable solution fail the Progress criterion?
Answer:
The Turn Variable solution enforces strict alternation (). If executes its critical section, it sets turn = 1. If does not wish to execute and remains in its remainder section, turn remains permanently. If wishes to enter the critical section a second time, it is blocked indefinitely by , even though the critical section is completely empty.
- The Inverted Line Order Trap in Peterson's Entry Section: If a programmer swaps the order of lines in Peterson's Entry Section:
A race condition occurs where both processes can observe
turn = 1; // Swapped!
flag[0] = true; // Swapped!flagas false and enter simultaneously. Intent (flag) must always be declared before yielding turn (turn). - Thinking Peterson's Algorithm Supports N Processes: Standard Peterson's Algorithm is strictly a two-process solution. Extending it to processes requires Filter's Algorithm or Lamport's Bakery Algorithm, or OS primitives like Semaphores.