Facebook Pixel

Bakery Algorithm for Process Synchronization

Leslie Lamport came up with this algorithm in 1974, and the inspiration behind it is surprisingly straightforward. Think about how a busy bakery manages its customers. Everyone walks in, grabs a numbered token, and waits for their number to be called. The person with the lowest number gets served first.

Lamport took that same idea and applied it to process synchronization. Unlike Peterson's and Dekker's algorithms which are limited to two processes, the Bakery Algorithm scales to any number of processes without any structural changes.

How It Works

Every process that wants to enter the critical section first picks up a ticket number. The number it picks is one higher than the highest number currently held by any other process. Once it has its number, it waits until all processes with lower numbers have finished. The one holding the smallest number goes in first.

There is one edge case worth mentioning. Two processes can occasionally end up with the same ticket number if they both pick at the same moment. When that happens, the tiebreaker is the process ID. The process with the lower ID gets priority.

The Shared Variables

Two shared arrays keep everything running:

  • choosing[i]: A boolean that signals whether Process i is currently in the middle of picking its number. Other processes need to know this so they do not compare numbers while someone is still choosing.
  • number[i]: The actual ticket number assigned to Process i. A value of zero means the process is not interested in entering the critical section right now.

Step by Step

When a process wants in, it goes through the following sequence:

text
Process i wants to enter:

  1. choosing[i] = true         // "I'm picking a number"
  2. number[i] = 1 + max(all numbers)   // Take the next ticket
  3. choosing[i] = false        // "Done picking"
       |
       v
  For each other process j:
       |
       +-- Wait until choosing[j] == false
       |   (Don't compare while they're still picking)
       |
       +-- Wait until:
           number[j] == 0              // j is not interested
           OR number[j] > number[i]    // j has a higher ticket
           OR (number[j] == number[i] AND j > i)  // Same ticket, but j has higher ID
       |
       v
  Enter Critical Section
       |
       v
  number[i] = 0                 // Discard the ticket
Why the choosing Array Matters
Without the choosing array, a subtle race condition can occur. Suppose Process A starts picking a number but has not finished yet. Process B checks A's number, sees it as 0 (not yet assigned), and proceeds into the critical section. Then A finishes picking and also enters, breaking mutual exclusion. The choosing flag prevents this by forcing B to wait until A has finished picking before making any comparisons.

The Code

cpp
#include <iostream>
#include <thread>
#include <vector>
#include <algorithm>
#include <atomic>
using namespace std;

const int NUM_PROCESSES = 5;
atomic<bool> choosing[NUM_PROCESSES];
atomic<int> number[NUM_PROCESSES];

void bakery_process(int i) {
    for (int iter = 0; iter < 5; iter++) {
        // Doorway: Pick a ticket number
        choosing[i] = true;
        number[i] = 1 + *max_element(number, number + NUM_PROCESSES);
        choosing[i] = false;

        // Wait for all other processes
        for (int j = 0; j < NUM_PROCESSES; j++) {
            while (choosing[j]);           // Wait if they're picking
            while (number[j] != 0 &&       // Wait if they have a ticket AND
                  (number[j] < number[i] || // their number is smaller, OR
                  (number[j] == number[i] && j < i)));  // same number but lower ID
        }

        // --- Critical Section ---
        cout << "Process " << i << " is in its critical section." << endl;

        // --- Exit Section ---
        number[i] = 0;                     // Discard the ticket
        cout << "Process " << i << " is in its remainder section." << endl;
    }
}

int main() {
    vector<thread> processes;
    for (int i = 0; i < NUM_PROCESSES; i++) {
        choosing[i] = false;
        number[i] = 0;
    }
    for (int i = 0; i < NUM_PROCESSES; i++) {
        processes.push_back(thread(bakery_process, i));
    }
    for (auto &process : processes) {
        process.join();
    }
    return 0;
}

Output:

text
Process 0 is in its critical section.
Process 0 is in its remainder section.
Process 1 is in its critical section.
Process 1 is in its remainder section.
...

What It Guarantees

RequirementHow the Bakery Algorithm Satisfies It
Mutual ExclusionOnly the process with the lowest ticket number enters. If two have the same number, the lower process ID wins. At most one process can satisfy both conditions simultaneously.
ProgressIf the critical section is free, the process with the lowest non-zero ticket number enters immediately. No external process can block it.
Bounded WaitingTicket numbers are assigned in increasing order. A process that picks a number will eventually hold the lowest number as others finish and discard their tickets.

What Makes It Worth Using

  • No Starvation: Since ticket numbers are assigned in order and every process eventually holds the lowest number, every process is guaranteed a turn. Nobody gets skipped indefinitely.
  • Fair by Design: Processes are served in the order they arrived (FCFS ordering), which is as fair as it gets. No priority system causes some processes to consistently jump ahead.
  • Scalability: Unlike Peterson's and Dekker's (limited to 2 processes), the Bakery Algorithm handles any number of processes without structural changes.
  • Intuitive Logic: The ticket number analogy makes the algorithm easy to understand even before looking at the code.

Bakery vs Peterson's vs Dekker's

FactorPeterson'sDekker'sBakery
Max Processes22N (unlimited)
Shared Variablesflag[2] + turnwant[2] + favouredchoosing[N] + number[N]
FairnessFair (alternating)Fair (favoured rotation)Strictly FCFS (ticket order)
Starvation FreeYesYesYes
OverheadLow (constant)Low (constant)Higher (O(N) scan per entry)
Historical Note1981, Gary Peterson1965, Th. J. Dekker (first ever)1974, Leslie Lamport

The Bakery Algorithm is one of those solutions that has held up well over time. It was designed in 1974 and is still a go-to reference for understanding how mutual exclusion can be achieved purely in software for multiple processes. For systems where you need fairness, no starvation, and the ability to scale beyond two processes, it covers all of those bases cleanly.

Bakery Algorithm Scenario

Question 1 of 1

Test your understanding of ticket-based synchronization.

Three processes pick ticket numbers at roughly the same time. Process A (ID=0) gets number 5, Process B (ID=1) gets number 5, and Process C (ID=2) gets number 3. In what order do they enter the critical section?
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.