Bakery Algorithm in Process Synchronization (original) (raw)

Last Updated : 25 Aug, 2025

The Bakery Algorithm, proposed by Leslie Lamport, is one of the simplest and most famous solutions to the mutual exclusion problem for N processes. It ensures fairness and follows a First-Come-First-Serve (FCFS) order.

How does the Bakery Algorithm work?

In the Bakery Algorithm, each process is assigned a number (a ticket) in a lexicographical order. Before entering the critical section, a process receives a ticket number, and the process with the smallest ticket number enters the critical section. If two processes receive the same ticket number, the process with the lower process ID is given priority.

How does the Bakery Algorithm ensure fairness?

The Bakery Algorithm ensures fairness by assigning a unique ticket number to each process based on a lexicographical order. This ensures that processes are served in the order they arrive, which guarantees that all processes will eventually enter the critical section.

if i < j
Pi is served first;
else
Pj is served first.

**Notation: lexicographical order (ticket #, process id #) - Firstly the ticket number is compared. If same then the process ID is compared next, i.e.-

– (a, b) < (c, d) if a < c or if a = c and b < d
– max(a [0], . . ., a [n-1]) is a number, k, such that k >= a[i] for i = 0, . . ., n - 1

Shared data - choosing is an array [0..n - 1] of boolean values; & number is an array [0..n - 1] of integer values. Both are initialized to **False & Zero respectively.

**Algorithm Pseudocode:

repeat

choosing[i] := true
number[i] := max(number[0..n-1]) + 1
choosing[i] := false

for j := 0 to n-1 do
while choosing[j] do skip // wait if other process is choosing
while number[j] ≠ 0 and (number[j], j) < (number[i], i) do skip

end for

critical section

number[i] := 0 // exit section
remainder section

until false

**Explanation :

**1. Choosing a ticket

**2. Waiting phase: For each process j

**3. Critical section: Process i enters when no other process has priority.
**4. Exit section: Number[i] := 0 process releases its ticket.
**5. Remainder section: Process does normal work, then repeats.
**6. Ensures: Mutual Exclusion, Fairness (FCFS), No Deadlock, No Starvation.

**Code: Here's the code implementation of the Bakery Algorithm. Run the following in a UNIX environment -

C++ `

#include #include #include #include #include #include

#define THREAD_COUNT 8

std::vector<std::atomic> tickets(THREAD_COUNT); std::vector<std::atomic> choosing(THREAD_COUNT); volatile int resource = 0;

std::mutex mtx; // Only for safe printing (not for algorithm itself)

// Lock function (Bakery algorithm) void lock(int thread) { choosing[thread].store(1, std::memory_order_relaxed);

// Find max ticket
int max_ticket = 0;
for (int i = 0; i < THREAD_COUNT; ++i) {
    int t = tickets[i].load(std::memory_order_relaxed);
    if (t > max_ticket) max_ticket = t;
}

// Assign ticket
tickets[thread].store(max_ticket + 1, std::memory_order_relaxed);
choosing[thread].store(0, std::memory_order_relaxed);

// Wait until it's this thread's turn
for (int other = 0; other < THREAD_COUNT; ++other) {
    if (other == thread) continue;

    // Wait if other thread is still choosing
    while (choosing[other].load(std::memory_order_relaxed)) {
        std::this_thread::yield();
    }
    
    // Wait if other has higher priority
    while (tickets[other].load(std::memory_order_relaxed) != 0 &&
          (tickets[other].load(std::memory_order_relaxed) < tickets[thread].load(std::memory_order_relaxed) ||
          (tickets[other].load(std::memory_order_relaxed) == tickets[thread].load(std::memory_order_relaxed) && other < thread))) {
        std::this_thread::yield();
    }

}

}

// Unlock function void unlock(int thread) { tickets[thread].store(0, std::memory_order_relaxed); }

// Simulated resource usage void use_resource(int thread) { std::lock_guardstd::mutex lock(mtx);

if (resource != 0) {
    std::cout << "ERROR: Thread " << thread
              << " entered while resource is in use by " << resource << "!\n";
}

resource = thread;
std::cout << "Thread " << thread << " using resource...\n";

std::this_thread::sleep_for(std::chrono::microseconds(50));
resource = 0;

}

// Thread function void thread_body(int thread) { lock(thread); use_resource(thread); unlock(thread); }

int main() { // Initialize tickets & choosing for (int i = 0; i < THREAD_COUNT; ++i) { tickets[i].store(0); choosing[i].store(0); } resource = 0;

std::vector<std::thread> threads;

// Create threads
for (int i = 0; i < THREAD_COUNT; ++i) {
    threads.emplace_back(thread_body, i);
}

// Wait for all threads
for (auto &t : threads) {
    t.join();
}

return 0;

} // Compile this code using the following command to link // against the pthread library: g++ -std=c++11 -pthread // Solution.cpp -o Solution

// Note: Ensure that you have the '-pthread' option to // properly link against the pthread library.

C

// Importing the thread library #include "pthread.h"

#include "stdio.h"

// Importing POSIX Operating System API library #include "unistd.h"

#include "string.h"

// This is a memory barrier instruction. // Causes compiler to enforce an ordering // constraint on memory operations. // This means that operations issued prior // to the barrier will be performed // before operations issued after the barrier. #define MEMBAR __sync_synchronize() #define THREAD_COUNT 8

volatile int tickets[THREAD_COUNT]; volatile int choosing[THREAD_COUNT];

// VOLATILE used to prevent the compiler // from applying any optimizations. volatile int resource;

void lock(int thread) {

// Before getting the ticket number
//"choosing" variable is set to be true
choosing[thread] = 1;

MEMBAR;
// Memory barrier applied

int max_ticket = 0;

// Finding Maximum ticket value among current threads
for (int i = 0; i < THREAD_COUNT; ++i) {

    int ticket = tickets[i];
    max_ticket
        = ticket > max_ticket ? ticket : max_ticket;
}

// Allotting a new ticket value as MAXIMUM + 1
tickets[thread] = max_ticket + 1;

MEMBAR;
choosing[thread] = 0;
MEMBAR;

// The ENTRY Section starts from here
for (int other = 0; other < THREAD_COUNT; ++other) {

    // Applying the bakery algorithm conditions
    while (choosing[other]) {
    }

    MEMBAR;

    while (tickets[other] != 0
           && (tickets[other] < tickets[thread]
               || (tickets[other] == tickets[thread]
                   && other < thread))) {
    }
}

}

// EXIT Section void unlock(int thread) {

MEMBAR;
tickets[thread] = 0;

}

// The CRITICAL Section void use_resource(int thread) {

if (resource != 0) {
    printf("Resource was acquired by %d, but is still "
           "in-use by %d!\n",
           thread, resource);
}

resource = thread;
printf("%d using resource...\n", thread);

MEMBAR;
sleep(2);
resource = 0;

}

// A simplified function to show the implementation void* thread_body(void* arg) {

long thread = (long)arg;
lock(thread);
use_resource(thread);
unlock(thread);
return NULL;

}

int main(int argc, char** argv) {

memset((void*)tickets, 0, sizeof(tickets));
memset((void*)choosing, 0, sizeof(choosing));
resource = 0;

// Declaring the thread variables
pthread_t threads[THREAD_COUNT];

for (int i = 0; i < THREAD_COUNT; ++i) {

    // Creating a new thread with the function
    //"thread_body" as its thread routine
    pthread_create(&threads[i], NULL, &thread_body,
                   (void*)((long)i));
}

for (int i = 0; i < THREAD_COUNT; ++i) {

    // Reaping the resources used by
    // all threads once their task is completed !
    pthread_join(threads[i], NULL);
}

return 0;

}

Java

import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;

public class Main { // Define the number of threads private static final int THREAD_COUNT = 8;

// Define tickets for each thread
private static AtomicInteger[] tickets
    = new AtomicInteger[THREAD_COUNT];

// Define choosing array to indicate if a thread is
// trying to enter the critical section
private static AtomicInteger[] choosing
    = new AtomicInteger[THREAD_COUNT];

// Define the shared resource
private static AtomicInteger resource
    = new AtomicInteger(0);

// Mutex for resource access
private static Lock mtx = new ReentrantLock();

public static void main(String[] args)
{
    // Initialize tickets and choosing arrays
    for (int i = 0; i < THREAD_COUNT; i++) {
        tickets[i] = new AtomicInteger(0);
        choosing[i] = new AtomicInteger(0);
    }

    // Initialize the shared resource
    resource.set(0);

    // Create threads
    Thread[] threads = new Thread[THREAD_COUNT];

    for (int i = 0; i < THREAD_COUNT; i++) {
        final int thread = i;
        threads[i] = new Thread(() -> {
            lock(thread); // Acquire the lock
            useResource(
                thread); // Use the shared resource
            unlock(thread); // Release the lock
        });
        threads[i].start(); // Start the thread
    }

    // Wait for all threads to finish
    for (Thread thread : threads) {
        try {
            thread.join();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// Method to acquire the lock
private static void lock(int thread)
{
    choosing[thread].set(
        1); // Indicate that the thread is trying to
            // enter the critical section

    // Find the maximum ticket number and assign the
    // next number to the current thread
    int maxTicket = 0;
    for (int i = 0; i < THREAD_COUNT; i++) {
        int ticket = tickets[i].get();
        maxTicket = Math.max(ticket, maxTicket);
    }

    tickets[thread].set(
        maxTicket + 1); // Assign the next ticket number
                        // to the current thread
    choosing[thread].set(0); // Indicate that the thread
                             // has got its ticket

    // Wait until all other threads have got their
    // tickets and it's the current thread's turn
    for (int other = 0; other < THREAD_COUNT; other++) {
        while (choosing[other].get() != 0) {
        }

        while (tickets[other].get() != 0
               && (tickets[other].get()
                       < tickets[thread].get()
                   || (tickets[other].get()
                           == tickets[thread].get()
                       && other < thread))) {
        }
    }
}

// Method to release the lock
private static void unlock(int thread)
{
    tickets[thread].set(
        0); // Reset the ticket of the current thread
}

// Method to use the shared resource
private static void useResource(int thread)
{
    mtx.lock(); // Acquire the mutex lock
    try {
        // Check if the resource is already in use
        if (resource.get() != 0) {
            System.out.println(
                "Resource was acquired by " + thread
                + ", but is still in-use by "
                + resource.get() + "!");
        }

        // Use the resource
        resource.set(thread);
        System.out.println(thread
                           + " using resource...");

        // Simulate the usage of the resource
        try {
            Thread.sleep(2000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Release the resource
        resource.set(0);
    }
    finally {
        mtx.unlock(); // Release the mutex lock
    }
}

}

C#

using System; using System.Threading;

public class Solution { private const int THREAD_COUNT = 8; private static int[] tickets = new int[THREAD_COUNT]; // Ticket array for each // thread private static int[] choosing = new int[THREAD_COUNT]; // Array to indicate if a // thread is choosing private static volatile int resource = 0; // Volatile resource variable private static object lockObj = new object(); // Lock object for synchronization

// Memory barrier instruction.
private static void Membar() { Thread.MemoryBarrier(); }

// Function to acquire the lock
private static void Lock(int thread)
{
    choosing[thread]
        = 1; // Indicate that this thread is choosing
    Membar(); // Memory barrier

    int maxTicket = 0;

    // Find the maximum ticket value
    for (int i = 0; i < THREAD_COUNT; i++) {
        int ticket = tickets[i];
        maxTicket = Math.Max(ticket, maxTicket);
    }

    // Assign ticket to this thread
    tickets[thread] = maxTicket + 1;

    Membar(); // Memory barrier
    choosing[thread] = 0; // Done choosing
    Membar(); // Memory barrier

    // The ENTRY Section starts from here
    for (int other = 0; other < THREAD_COUNT; ++other) {
        // Applying the bakery algorithm conditions
        while (choosing[other] != 0) {
        }

        Membar();

        while (tickets[other] != 0
               && (tickets[other] < tickets[thread]
                   || (tickets[other] == tickets[thread]
                       && other < thread))) {
        }
    }
}

// EXIT Section
private static void Unlock(int thread)
{
    Membar();
    tickets[thread] = 0;
}

// The CRITICAL Section
private static void UseResource(int thread)
{
    lock(lockObj) // Lock to ensure thread-safe access
                  // to resource
    {
        // Check if resource is already in use
        if (resource != 0) {
            Console.WriteLine(
                $
                "Resource was acquired by {thread}, but is still in-use by {resource}!");
        }

        // Acquire resource
        resource = thread;
        Console.WriteLine($
                          "{thread} using resource...");
    }

    // Simulate resource usage
    Thread.Sleep(TimeSpan.FromSeconds(2));

    // Release resource
    lock(lockObj) { resource = 0; }
}

// A simplified function to show the implementation
private static void ThreadBody(object arg)
{
    long thread = (long)arg;
    Lock((int)thread); // Acquire lock
    UseResource((int)thread); // Use resource
    Unlock((int)thread); // Release lock
}

public static void Main(string[] args)
{
    Array.Clear(
        tickets, 0,
        THREAD_COUNT); // Initialize ticket array
    Array.Clear(
        choosing, 0,
        THREAD_COUNT); // Initialize choosing array
    resource = 0; // Initialize resource

    Thread[] threads = new Thread[THREAD_COUNT];

    for (int i = 0; i < THREAD_COUNT; ++i) {
        threads[i] = new Thread(ThreadBody);
        threads[i].Start(i);
    }

    for (int i = 0; i < THREAD_COUNT; ++i) {
        threads[i].Join();
    }
}

}

` JavaScript ``

const THREAD_COUNT = 8; const tickets = new Array(THREAD_COUNT).fill(0); const choosing = new Array(THREAD_COUNT).fill(0); let resource = 0; const lockObj = {};

// Memory barrier instruction. function membar() { // JavaScript doesn't have explicit memory barrier instructions. // In most cases, JavaScript's single-threaded //nature makes explicit memory barriers unnecessary. // If working with Web Workers or other asynchronous operations, // additional synchronization may be required. }

// Function to acquire the lock function lock(thread) { choosing[thread] = 1; membar();

let maxTicket = 0;

// Find the maximum ticket value for (let i = 0; i < THREAD_COUNT; i++) { const ticket = tickets[i]; maxTicket = Math.max(ticket, maxTicket); }

// Assign ticket to this thread tickets[thread] = maxTicket + 1;

membar(); choosing[thread] = 0; membar();

// The ENTRY Section starts from here for (let other = 0; other < THREAD_COUNT; ++other) { while (choosing[other] !== 0) {}

membar();

while (tickets[other] !== 0 && (tickets[other] < 
tickets[thread] || (tickets[other] === tickets[thread] && 
other < thread))) {}

} }

// EXIT Section function unlock(thread) { membar(); tickets[thread] = 0; }

// The CRITICAL Section function useResource(thread) { lockObj.lock = true;

// Check if resource is already in use if (resource !== 0) { console.log(Resource was acquired by ${thread}, but is still in-use by ${resource}!); }

// Acquire resource resource = thread; console.log(${thread} using resource...);

// Simulate resource usage setTimeout(() => { // Release resource resource = 0; lockObj.lock = false; }, 2000); }

// A simplified function to show the implementation function threadBody(thread) { lock(thread); useResource(thread); unlock(thread); }

const threads = [];

for (let i = 0; i < THREAD_COUNT; ++i) { threads[i] = setTimeout(threadBody, 0, i); } //This code is contributed by Aman.

// Note: This code uses setTimeout to simulate threads, // but for actual multithreading in JavaScript, // you would need to use a library or environment that supports it, // such as Node.js with Worker Threads // or a web browser environment with Web Workers. // use this node multithreading.js

``

**Output: Output

Advantages of Bakery Algorithm

Disadvantages Bakery Algorithm