#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
#include <chrono>
#include <algorithm>
using namespace std;
const int NUM_CUSTOMERS = 5;
atomic<bool> choosing[NUM_CUSTOMERS];
atomic<int> number[NUM_CUSTOMERS];
// Utility: Get max ticket number
int get_max_ticket() {
int max_val = 0;
for (int i = 0; i < NUM_CUSTOMERS; ++i) {
max_val = max(max_val, number[i].load());
}
return max_val;
}
// Bakery Lock
void lock(int id) {
choosing[id] = true;
cout << "Customer " << id << " is choosing a ticket...\n";
number[id] = get_max_ticket() + 1;
choosing[id] = false;
cout << "Customer " << id << " got ticket #" << number[id] << " and is waiting to enter...\n";
for (int j = 0; j < NUM_CUSTOMERS; ++j) {
while (choosing[j]) {} // wait while another customer is choosing
while (number[j] != 0 &&
(number[j] < number[id] ||
(number[j] == number[id] && j < id))) {
// busy wait
}
}
}
// Bakery Unlock
void unlock(int id) {
number[id] = 0;
}
// Critical Section Simulation
void critical_section(int id) {
lock(id);
cout << "Customer " << id << " is ENTERING critical section.\n";
this_thread::sleep_for(chrono::milliseconds(rand() % 1500 + 500));
cout << "Customer " << id << " is EXITING critical section.\n\n";
unlock(id);
}
int main() {
// Initialize arrays
for (int i = 0; i < NUM_CUSTOMERS; ++i) {
choosing[i] = false;
number[i] = 0;
}
// Launch customer threads
vector<thread> customers;
for (int i = 0; i < NUM_CUSTOMERS; ++i) {
customers.emplace_back(critical_section, i);
this_thread::sleep_for(chrono::milliseconds(300)); // staggered arrival
}
for (auto& c : customers) {
c.join();
}
return 0;
}