- OS - Home
- OS - Needs
- OS - Overview
- OS - History
- OS - Components
- OS - Structure
- OS - Architecture
- OS - Services
- OS - Properties
- Process Management
- Processes in Operating System
- States of a Process
- Process Schedulers
- Process Control Block
- Operations on Processes
- Inter Process Communication (IPC)
- Context Switching
- Multi-threading
- Scheduling Algorithms
- Process Scheduling
- Types of Scheduling
- Scheduling Algorithms Overview
- FCFS Scheduling Algorithm
- SJF Scheduling Algorithm
- Round Robin Scheduling Algorithm
- HRRN Scheduling Algorithm
- Priority Scheduling Algorithm
- Multilevel Queue Scheduling
- Lottery Scheduling Algorithm
- Starvation and Aging
- Turn Around Time & Waiting Time
- Burst Time in SJF Scheduling
- Process Synchronization
- Process Synchronization
- Solutions For Process Synchronization
- Hardware-Based Solution
- Software-Based Solution
- Critical Section Problem
- Critical Section Synchronization
- Mutual Exclusion Synchronization
- Peterson's Algorithm
- Dekker's Algorithm
- Bakery Algorithm
- Semaphores
- Binary Semaphores
- Counting Semaphores
- Mutex
- Turn Variable
- Bounded Buffer Problem
- Reader Writer Locks
- Test and Set Lock
- Monitors
- Sleep and Wake
- Race Condition
- OS Deadlock
- Introduction to Deadlock
- Conditions for Deadlock
- Deadlock Handling
- Deadlock Prevention
- Deadlock Avoidance (Banker's Algorithm)
- Deadlock Detection and Recovery
- Deadlock Ignorance
- Memory Management
- Memory Management
- Contiguous Memory Allocation
- Non-Contiguous Memory Allocation
- First Fit Algorithm
- Next Fit Algorithm
- Best Fit Algorithm
- Worst Fit Algorithm
- Fragmentation
- Virtual Memory
- Segmentation
- Buddy System
- Slab Allocation
- Overlays
- Paging and Page Replacement
- Paging
- Demand Paging
- Page Table
- Page Replacement Algorithms
- Optimal Page Replacement Algorithm
- Belady's Anomaly
- Thrashing
- Storage and File Management
- File Systems
- File Attributes
- Structures of Directory
- Linked Index Allocation
- Indexed Allocation
- Disk Scheduling Algorithms
- FCFS Disk Scheduling
- SSTF Disk Scheduling
- SCAN Disk Scheduling
- LOOK Disk Scheduling
- I/O Systems
- I/O Hardware
- I/O Software
- OS Types
- OS - Types
- OS - Batch Processing
- OS - Multiprocessing
- OS - Hybrid
- OS - Monolithic
- OS - Zephyr
- OS - Nix
- OS - Linux
- OS - Blackberry
- OS - Garuda
- OS - Tails
- OS - Clustered
- OS - Haiku
- OS - AIX
- OS - Solus
- OS - Tizen
- OS - Bharat
- OS - Fire
- OS - Bliss
- OS - VxWorks
- OS - Embedded
- OS - Single User
- Miscellaneous Topics
- OS - Security
- OS Questions Answers
- OS - Questions Answers
- OS Useful Resources
- OS - Quick Guide
- OS - Useful Resources
- OS - Discussion
Operating System - Peterson Solution in Process Synchronization
The process synchronization is a mechanism of synchronizing multiple processes to ensure that they can run without interfering with each other. If multiple processes access shared resources concurrently, it may lead to data inconsistency and unexpected results. To avoid such issues, various synchronization algorithms have been developed.
Peterson's Algorithm is a classic software-based solution for achieving mutual exclusion and synchronization between two processes. It was proposed by Gary L. Peterson in 1981. This chapter will explain the working of Peterson's Algorithm and how it ensures process synchronization.
The Peterson's Algorithm
The idea behind Peterson's Algorithm is to use two shared variables to indicate the intention of each process to enter its critical section. The two variables are −
- flag[i] − A boolean variable that indicates whether process i wants to enter its critical section.
- turn − An integer variable that indicates whose turn it is to enter the critical section.
The following are the steps or processes for Peterson's Algorithm −
- Set the turn to either 0 or 1 to indicating which process can enter its critical section first.
- Set flag[i] to true, indicating that process i wants to enter its critical section.
- Set turn to j, the index of the other process.
- While flag[j] is true and turn equals j, wait.
- Enter the critical section.
- Set flag[i] to false, indicating that process i has finished its critical section.
- Remainder section.
In this algorithm, each process sets its flag to true when it wants to enter the critical section. It then sets the turn variable to the other process, indicating that it is willing to let the other process enter first. The process then enters a busy-wait loop, checking if the other process is interested in entering its critical section and if it's the other process's turn. If both conditions are true, the process waits. Once it can proceed, it enters its critical section.
Properties of Peterson's Algorithm
Peterson's Algorithm satisfies the following properties −
- Mutual Exclusion − Only one process can be in its critical section at a time.
- Progress − If no process is in its critical section, and one or more processes want to enter their critical sections, then the selection of the next process to enter the critical section cannot be postponed indefinitely.
- Bounded Waiting − There exists a limit on the number of times other processes are allowed to enter their critical sections after a process has made a request to enter its critical section and before that request is granted.
Implementation of Peterson's Algorithm
Peterson's Algorithm can be implemented in various programming languages.
import threading
flag = [False, False]
turn = 0
def peterson_process(i):
global flag, turn
j = 1 - i
count = 0
while True:
# Indicate that process i wants to enter its critical section
flag[i] = True
# Set turn to the other process
turn = j
# Wait until the other process is not interested or it's this process's turn
while flag[j] and turn == j:
pass # Busy wait
# Critical Section
print(f"Process {i} in critical section")
# Exit Section
flag[i] = False
# Remainder Section
print(f"Process {i} in remainder section")
count += 1
# Limit the number of iterations for demonstration
if count >= 5:
break
# Create two threads for the two processes
thread1 = threading.Thread(target=peterson_process, args=(0,))
thread2 = threading.Thread(target=peterson_process, args=(1,))
thread1.start()
thread2.start()
The output of the above code will be −
Process 0 in critical section Process 0 in remainder section Process 1 in critical section Process 1 in remainder section ...
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<bool> flag[2] = {false, false};
atomic<int> turn;
void peterson_process(int i) {
int j = 1 - i;
while (true) {
// Indicate that process i wants to enter its critical section
flag[i] = true;
// Set turn to the other process
turn = j;
// Wait until the other process is not interested or it's this process's turn
while (flag[j] && turn == j) {
// Busy wait
}
// Critical Section
cout << "Process " << i << " in critical section" << endl;
// Exit Section
flag[i] = false;
// Remainder Section
cout << "Process " << i << " in remainder section" << endl;
}
}
int main() {
thread t1(peterson_process, 0);
thread t2(peterson_process, 1);
t1.join();
t2.join();
return 0;
}
The output of the above code will be −
Process 0 in critical section Process 0 in remainder section Process 1 in critical section Process 1 in remainder section ...
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class PetersonsAlgorithm {
private static AtomicBoolean[] flag = {new AtomicBoolean(false), new AtomicBoolean(false)};
private static AtomicInteger turn = new AtomicInteger(0);
public static void petersonProcess(int i) {
int j = 1 - i;
while (true) {
// Indicate that process i wants to enter its critical section
flag[i].set(true);
// Set turn to the other process
turn.set(j);
// Wait until the other process is not interested or it's this process's turn
while (flag[j].get() && turn.get() == j) {
// Busy wait
}
// Critical Section
System.out.println("Process " + i + " in critical section");
// Exit Section
flag[i].set(false);
// Remainder Section
System.out.println("Process " + i + " in remainder section");
}
}
public static void main(String[] args) {
Thread t1 = new Thread(() -> petersonProcess(0));
Thread t2 = new Thread(() -> petersonProcess(1));
t1.start();
t2.start();
}
}
The output of the above code will be −
Process 0 in critical section Process 0 in remainder section Process 1 in critical section Process 1 in remainder section ...
Example Use Cases of Peterson's Algorithm
Peterson's Algorithm can be used in various situations where process synchronization is required. Some common use cases include −
- Accessing Shared Resources − When two entities need to access shared resources like files, databases, or memory, Peterson's Algorithm can ensure that only one entity accesses the resource at a time. For example, peterson algorithm can be used to synchronize access of printer to two processes.
- Prevent Deadlocks − Peterson's Algorithm prevent deadlocks by ensuring mutual exclusion and bounded waiting.
- Real-Time Systems − In real-time systems, peterson's algorithm can be used to ensure that critical tasks are executed without interference from other tasks.
Conclusion
Peterson's Algorithm is a simple and effective solution for achieving process synchronization and mutual exclusion between two processes. By using shared variables to indicate the intention of each process to enter its critical section, the algorithm ensures that only one process can access the critical section at a time.