PROCESS SYNCHRONIZATION — CRITICAL SECTION, SEMAPHORES, PETERSON'S ALGORITHM & PRODUCER–CONSUMER
1(a). Explain the Critical Section Problem and discuss the requirements for a correct solution. Describe suitable synchronization mechanisms with examples.
1. Critical Section Problem

A critical section is the part of a process where it accesses or modifies shared data or a shared resource.

When multiple processes execute concurrently, two or more processes may try to access the same shared resource at the same time. This can produce incorrect or inconsistent results.

Basic structure of a process
┌──────────────────┐
        │ Entry Section    │
        └────────┬─────────┘
                 ↓
        ┌──────────────────┐
        │ Critical Section │
        │                  │
        │ Access Shared    │
        │ Data / Resource  │
        └────────┬─────────┘
                 ↓
        ┌──────────────────┐
        │ Exit Section     │
        └────────┬─────────┘
                 ↓
        ┌──────────────────┐
        │ Remainder        │
        │ Section          │
        └──────────────────┘
Four parts

Entry Section:
A process requests permission to enter the critical section.

Critical Section:
The process accesses the shared resource.

Exit Section:
The process releases the critical section.

Remainder Section:
The process performs other operations that do not involve shared resources.

2. Example of the Critical Section Problem

Suppose two processes, P1 and P2, want to increment the same variable:

Shared variable:
count = 5

Both execute:

count = count + 1

This operation actually involves multiple steps:

Read count
     ↓
Add 1
     ↓
Write count

Suppose both processes execute at the same time:

P1: Read count = 5
P2: Read count = 5

P1: Add 1 → 6
P2: Add 1 → 6

P1: Write 6
P2: Write 6

Expected result:

7

Actual result:

6

This is called a race condition.

Key point

> Race Condition = Result depends on the order/timing of process execution.

The critical-section problem aims to prevent such incorrect access to shared data.

3. Requirements of a Correct Critical-Section Solution

A correct solution must satisfy three important requirements.

A. Mutual Exclusion

If one process is executing inside its critical section, no other process can enter its critical section.

P1 → CRITICAL SECTION
             ↑
       P2 must wait

Example

If P1 is updating a shared bank account, P2 must wait until P1 finishes.

🧠 Remember:

> Mutual Exclusion = ONE process at a time
B. Progress

If no process is currently inside the critical section, and some processes want to enter, the selection of the next process should not be unnecessarily delayed.

Critical Section = FREE

P1 wants to enter
P2 wants to enter

        ↓

One of them should be selected

A process outside its critical section should not unnecessarily prevent another process from entering.

🧠 Remember:

> Progress = If it's free, someone should be allowed to enter.
C. Bounded Waiting

A process requesting entry should not have to wait forever.

There must be a limit on the number of times other processes can enter before the waiting process gets its turn.

P1 waiting
   ↓
P2 enters
   ↓
P3 enters
   ↓
P4 enters
   ↓
P1 keeps waiting forever ❌

A correct solution prevents this situation.

🧠 Remember:

> Bounded Waiting = Nobody waits forever
4. Synchronization Mechanisms

Operating systems provide different mechanisms to solve critical-section and synchronization problems.

Important mechanisms include:

  1. Mutex Locks
  2. Semaphores
  3. Monitors
  4. Hardware Atomic Instructions
A. Mutex Lock

A mutex (mutual exclusion) lock allows only one process/thread to access a critical section at a time.

It has two basic operations:

acquire()
release()

Working

Process
   ↓
acquire lock
   ↓
Critical Section
   ↓
release lock

Example

acquire(lock);

balance = balance + 100;

release(lock);

If another process tries to acquire the locked mutex, it must wait.

🧠 Remember:

> Mutex = Lock the door → Enter → Work → Unlock
B. Semaphore

A semaphore is a synchronization variable used to control access to shared resources.

Two main operations are:

wait()
signal()

Example

wait(S);

Critical Section;

signal(S);

If S indicates that a resource is unavailable, the process waits.

After finishing its work, the process performs signal() to indicate that the resource is available.

Types of Semaphores

Binary Semaphore

It can have values:

0 or 1

It is commonly used for mutual exclusion.

Counting Semaphore

It can have values:

0, 1, 2, 3, ...

It is useful when there are multiple identical resources.

Example

If there are 3 printers:

S = 3

Each process uses:

wait(S)

When a printer is released:

signal(S)
C. Monitor

A monitor is a high-level synchronization mechanism that combines:

Shared data
Procedures
Synchronization

Only one process can execute inside a monitor at a time.

Basic idea

MONITOR
┌─────────────────────┐
│ Shared Data         │
│                     │
│ Procedure 1         │
│ Procedure 2         │
│ Procedure 3         │
└─────────────────────┘
          ↑
      Processes

Monitors provide mutual exclusion automatically, making synchronization easier for programmers.

D. Hardware-Based Synchronization

Modern processors provide special atomic instructions that can be used to implement mutual exclusion.

Examples:

Test-and-Set

Compare-and-Swap

These operations are performed atomically, meaning they cannot be interrupted halfway.

Example: Test-and-Set

while (TestAndSet(lock))
    ;       // wait

Critical Section

lock = false;

If the lock is already set, the process waits.

If it is free, the process acquires it.

5. Comparison of Synchronization Mechanisms
Mechanism Main Purpose Important Feature
Mutex Mutual exclusion Lock/Unlock
Binary Semaphore Mutual exclusion 0 or 1
Counting Semaphore Resource management Multiple values
Monitor High-level synchronization One process inside
Hardware Instructions Low-level synchronization Atomic operations
🧠 Easy Memory for the Entire Answer

Critical Section:

Entry → Critical → Exit → Remainder

Requirements:

M → P → B

> Mutual Exclusion → Progress → Bounded Waiting

Synchronization:

> Mutex → Semaphore → Monitor → Hardware
1(b). Analyze the Role of Semaphores in Process Synchronization. Explain wait() and signal() Operations with Suitable Examples and Discuss Their Application in Solving Synchronization Problems.
1. Semaphore

A semaphore is a synchronization tool used by the operating system to control access to shared resources and coordinate concurrent processes.

A semaphore is generally represented by an integer variable:

S

Processes do not directly modify the semaphore. They use two atomic operations:

wait(S)
signal(S)

These operations are also commonly represented as:

P(S) → wait
V(S) → signal
2. Types of Semaphores
A. Binary Semaphore

A binary semaphore has only two possible values:

0 → Resource unavailable
1 → Resource available

It is commonly used for mutual exclusion.

Example

Semaphore S = 1

P1 → wait(S)
     Critical Section
     signal(S)

P2 → wait(S)
     Critical Section
     signal(S)

Only one process can enter at a time.

B. Counting Semaphore

A counting semaphore can have values greater than 1.

It is useful when there are multiple instances of a resource.

Example

Suppose there are 3 identical printers:

S = 3

Three processes can obtain printers.

When all three printers are occupied:

S = 0

The next process must wait.

3. wait() Operation

The wait() operation is used when a process wants to acquire a resource.

Conceptually:

wait(S)
{
    while (S <= 0)
        wait;

    S--;
}

The actual implementation uses atomic synchronization; the above is only a simplified representation.

Meaning

If the resource is available:

S > 0

the process can proceed and the semaphore is decreased.

If the resource is unavailable:

S = 0

the process waits.

🧠 Remember:

> wait() = Ask for / Acquire resource
4. signal() Operation

The signal() operation is used when a process releases a resource.

Conceptually:

signal(S)
{
    S++;
}

A waiting process may then be allowed to proceed.

🧠 Remember:

> signal() = Release / Notify
5. Semaphore Example for Mutual Exclusion

Suppose two processes access a shared variable.

Initialize:

S = 1

Process P1

wait(S);

      // Critical Section
      shared_data++;

signal(S);

Process P2

wait(S);

      // Critical Section
      shared_data++;

signal(S);

Working

P1 → wait(S) → Critical Section → signal(S)
                                      ↓
P2 → wait(S) → Critical Section → signal(S)

If P1 is inside the critical section, P2 must wait.

Thus, the semaphore provides mutual exclusion.

6. Semaphore for Resource Sharing

Suppose a system has:

3 printers

Initialize:

printer = 3

When a process wants a printer:

wait(printer);

When it finishes:

signal(printer);

Working

3 printers available

P1 → wait → Printer 1
P2 → wait → Printer 2
P3 → wait → Printer 3

P4 → wait → Must wait

P1 → signal → Printer released

P4 → Gets printer

This allows the OS to control the number of processes using the resource.

7. Applications of Semaphores

Semaphores are used to solve several synchronization problems.

A. Critical Section Problem

Ensures that only one process accesses shared data at a time.

wait(mutex);

Critical Section

signal(mutex);
B. Producer–Consumer Problem

Semaphores coordinate producers and consumers sharing a common buffer.

Typical semaphores:

empty
full
mutex

Where:

empty → Number of empty buffer spaces

full → Number of filled buffer spaces

mutex → Protects the buffer

C. Reader–Writer Problem

Semaphores can coordinate readers and writers accessing shared data.

They ensure that writers do not modify data while conflicting accesses are occurring.

D. Resource Management

Counting semaphores can control access to a fixed number of resources.

Example:

Printers
Database connections
Memory buffers
8. Important Semaphore Rules

A semaphore operation should be atomic.

That means:

> wait() and signal() must execute as indivisible operations.

Otherwise, two processes could modify the semaphore simultaneously and create synchronization errors.

🧠 Easy Memory

Semaphore = Traffic Police 🚦

Think of a semaphore as a traffic controller.

Resource available
       ↓
    wait()
       ↓
   Process enters
       ↓
 Critical Section
       ↓
   signal()
       ↓
 Resource released
One-line memory:

> wait() → Enter / Acquire
signal() → Exit / Release
2(a). Explain the Critical Section Problem and Discuss Peterson's Algorithm and a Hardware-Based Solution for Achieving Mutual Exclusion, with Suitable Examples.
1. Critical Section Problem

A critical section is the portion of a process where it accesses or modifies shared data or resources.

When multiple processes execute concurrently, simultaneous access can result in a race condition.

Structure

┌─────────────────┐
│ Entry Section   │
└────────┬────────┘
         ↓
┌─────────────────┐
│ Critical       │
│ Section        │
└────────┬────────┘
         ↓
┌─────────────────┐
│ Exit Section    │
└────────┬────────┘
         ↓
┌─────────────────┐
│ Remainder       │
│ Section         │
└─────────────────┘
2. Race Condition

A race condition occurs when multiple processes access shared data simultaneously and the final result depends on execution timing.

Example

count = 10

Two processes execute:

count = count + 1

Both may read 10 before either writes the result.

P1 reads 10
P2 reads 10

P1 writes 11
P2 writes 11

Expected:

12

Actual:

11

Therefore, access to count must be protected.

3. Requirements of Critical Section Solution

A correct solution must satisfy:

Mutual Exclusion

Only one process can execute its critical section at a time.

Progress

If the critical section is free, a process that wants to enter should not be unnecessarily delayed.

Bounded Waiting

A process should not wait indefinitely to enter its critical section.

🧠 Memory:

> MPB = Mutual → Progress → Bounded
4. Peterson's Algorithm

Peterson's Algorithm is a software-based solution for achieving mutual exclusion between two processes.

The two processes are usually:

P0
P1

It uses two shared variables:

boolean flag[2];
int turn;

flag[i]

Indicates whether process Pi wants to enter the critical section.

flag[i] = true

means:

> Process Pi wants to enter.

turn

Indicates whose turn it is to enter if both processes want to enter.

5. Peterson's Algorithm — Basic Code

For process Pi:

flag[i] = true;
turn = j;

while (flag[j] && turn == j)
    ;       // wait

// Critical Section

flag[i] = false;

// Remainder Section

Where:

i = current process
j = other process
6. Peterson's Algorithm for P0
flag[0] = true;
turn = 1;

while (flag[1] && turn == 1)
    ;

// Critical Section

flag[0] = false;
7. Peterson's Algorithm for P1
flag[1] = true;
turn = 0;

while (flag[0] && turn == 0)
    ;

// Critical Section

flag[1] = false;
8. Working of Peterson's Algorithm

Suppose both P0 and P1 want to enter.

P0:

flag[0] = true
turn = 1

P1:

flag[1] = true
turn = 0

Both have indicated that they want to enter.

The turn variable determines which process gets priority.

One process enters the critical section while the other waits.

After the first process finishes:

flag[i] = false

The waiting process can enter.

9. Why Peterson's Algorithm Works

Peterson's algorithm satisfies the three requirements:

Mutual Exclusion

Only one process can enter the critical section at a time.

Progress

If only one process wants to enter, it can enter without unnecessary delay.

Bounded Waiting

A process will not be postponed forever.

🧠 Easy memory:

> Flag = "I want to enter"
Turn = "You go first"
10. Hardware-Based Solution

Modern processors provide special atomic instructions to implement mutual exclusion.

Two important examples are:

Test-and-Set

Compare-and-Swap

These instructions perform their operation atomically.

Atomic means:

> The operation happens as one indivisible unit.

Another processor cannot interrupt the operation halfway through.

11. Test-and-Set

A simple Test-and-Set operation can be represented as:

boolean TestAndSet(boolean *target)
{
    boolean old = *target;
    *target = true;
    return old;
}

A lock is initially:

lock = false

Process:

while (TestAndSet(&lock))
    ;

// Critical Section

lock = false;
12. Working of Test-and-Set

Suppose:

lock = false

P1 executes:

TestAndSet(lock)

It gets:

old = false

and sets:

lock = true

Therefore, P1 enters the critical section.

If P2 tries while P1 is inside:

lock = true

P2 keeps waiting.

After P1 finishes:

lock = false

P2 can enter.

13. Peterson vs Hardware Solution
Peterson's Algorithm Hardware Solution
Software-based Hardware-supported
Mainly designed for two processes Can support synchronization in modern multiprocessor systems
Uses flag and turn Uses atomic instructions
No special hardware instruction required Requires processor atomic instruction support
🧠 Easy Memory

Peterson:

> FLAG + TURN

Flag: I want to enter.

Turn: You go first.

Hardware:

> Test → Set → Lock
2(b). Explain Semaphores and their Implementation. Illustrate How Semaphores are Used to Solve the Producer–Consumer (Bounded Buffer) Problem.
1. Semaphore

A semaphore is a synchronization variable used to control access to shared resources and coordinate concurrent processes.

It is accessed using two atomic operations:

wait()
signal()
2. Types of Semaphores
Binary Semaphore

A binary semaphore has only:

0 or 1

It is commonly used to achieve mutual exclusion.

Example:

mutex = 1
Counting Semaphore

A counting semaphore can have values:

0, 1, 2, 3, ...

It is used when there are multiple instances of a resource.

Example:

3 printers → semaphore = 3
3. Semaphore Implementation

A semaphore can be represented as:

typedef struct {
    int value;
    process waiting_queue;
} semaphore;

The semaphore has:

Value → Represents resource availability.

Waiting queue → Holds processes waiting for the resource.

The operations must be atomic.

4. Wait Operation

Conceptually:

wait(S)
{
    S--;

    if (S < 0)
    {
        add process to waiting queue;
        block();
    }
}

The process is blocked if the required resource is unavailable.

🧠 Memory:

> wait = Try to get resource
5. Signal Operation

Conceptually:

signal(S)
{
    S++;

    if (S <= 0)
    {
        remove process from waiting queue;
        wakeup(process);
    }
}

It releases the resource and can wake a waiting process.

🧠 Memory:

> signal = Give back resource
6. Producer–Consumer Problem

The Producer–Consumer problem, also called the Bounded Buffer problem, involves:

A Producer

A Consumer

A Shared Buffer
Producer

Produces items and places them into the buffer.

Consumer

Removes items from the buffer and consumes them.

Buffer

Stores items temporarily.

Producer
    │
    │ produces
    ↓
┌──────────────────────┐
│    BOUNDED BUFFER    │
│ [ ][ ][ ][ ][ ]      │
└──────────────────────┘
    │
    │ consumes
    ↓
Consumer
7. Problems in Producer–Consumer

Two important problems must be prevented.

Problem 1: Buffer Overflow

The producer must not add an item when the buffer is full.

Buffer = FULL
     ↓
Producer must WAIT

Problem 2: Buffer Underflow

The consumer must not remove an item when the buffer is empty.

Buffer = EMPTY
     ↓
Consumer must WAIT

There is also a third requirement:

Mutual Exclusion

Producer and consumer should not modify the shared buffer simultaneously.

8. Semaphores Used

Three semaphores are commonly used:

mutex
empty
full

mutex

Used for mutual exclusion.

mutex = 1

Only one process can access the buffer at a time.

empty

Represents the number of empty slots.

If buffer size is N:

empty = N

full

Represents the number of filled slots.

Initially:

full = 0
9. Producer Algorithm

The producer follows:

while (true)
{
    item = produce_item();

    wait(empty);
    wait(mutex);

    insert_item(item);

    signal(mutex);
    signal(full);
}

Explanation

wait(empty)

Checks whether an empty buffer slot exists.

If the buffer is full, producer waits.

wait(mutex)

Locks the buffer so that only the producer can modify it.

insert_item()

Adds the item to the buffer.

signal(mutex)

Releases the buffer.

signal(full)

Increases the number of filled slots and allows a waiting consumer to proceed.

10. Consumer Algorithm

The consumer follows:

while (true)
{
    wait(full);
    wait(mutex);

    item = remove_item();

    signal(mutex);
    signal(empty);

    consume_item(item);
}

Explanation

wait(full)

Checks whether at least one item is available.

If the buffer is empty, consumer waits.

wait(mutex)

Locks the buffer.

remove_item()

Removes an item.

signal(mutex)

Releases the buffer.

signal(empty)

Indicates that one empty buffer slot is now available.

11. Complete Producer–Consumer Diagram
PRODUCER
                     │
                     │
              produce item
                     │
                     ↓
              wait(empty)
                     │
                     ↓
              wait(mutex)
                     │
                     ↓
             ┌──────────────┐
             │    BUFFER    │
             │ [ ][X][X][ ] │
             └──────────────┘
                     │
                     ↓
              signal(mutex)
                     │
                     ↓
                signal(full)
                     │
                     ↓
                 CONSUMER

The consumer performs the reverse operations:

Consumer
   ↓
wait(full)
   ↓
wait(mutex)
   ↓
Remove item
   ↓
signal(mutex)
   ↓
signal(empty)
12. Example

Suppose the buffer has 5 slots.

Initially:

empty = 5
full = 0
mutex = 1

Producer adds one item:

empty = 4
full = 1

Consumer removes that item:

empty = 5
full = 0

If all five slots become occupied:

empty = 0
full = 5

The producer executes:

wait(empty)

and must wait.

If the consumer removes an item:

empty = 1
full = 4

The producer can now continue.

13. Why Three Semaphores Are Needed
Semaphore Initial Value Purpose
mutex 1 Protects shared buffer
empty N Counts empty slots
full 0 Counts filled slots
🧠 The easiest way to remember:

> EMPTY = Can Producer enter?
FULL = Can Consumer enter?
MUTEX = Who can touch the buffer?
🔥 FINAL MEMORY MAP — PROCESS SYNCHRONIZATION

For these four long questions, remember this structure:

PROCESS SYNCHRONIZATION
                      │
       ┌──────────────┴──────────────┐
       ↓                             ↓
 CRITICAL SECTION               SEMAPHORES
       │                             │
       ├─ Race Condition             ├─ wait()
       │                             ├─ signal()
       ├─ Mutual Exclusion           ├─ Binary
       ├─ Progress                   └─ Counting
       └─ Bounded Waiting
       │
       ├──────────────┐
       ↓              ↓
  PETERSON       HARDWARE
       │              │
 FLAG + TURN    Test-and-Set
                       │
                       ↓
                PRODUCER-CONSUMER
                       │
              ┌────────┼────────┐
              ↓        ↓        ↓
            EMPTY     FULL     MUTEX
              │        │        │
           Producer  Consumer  Buffer
            waits     waits    protection
@Thinking
3(a). Explain the Deadlock Problem in Detail. Discuss the System Model, Deadlock Characterization, and the Four Necessary Conditions for Deadlock with Suitable Examples.
1. Deadlock Problem

A deadlock is a situation in which a group of processes are permanently blocked, because every process is waiting for a resource held by another process in the same group.

Simple example

Suppose there are two processes and two resources:

P1 has Printer  → wants Scanner
P2 has Scanner  → wants Printer

Now:

P1 → waiting for Scanner → held by P2
P2 → waiting for Printer → held by P1

Neither process can continue.

P1
       /  \
      ↓    ↑
  Printer  Scanner
      ↑    ↓
       \  /
        P2

This is a deadlock.

Easy memory

> Deadlock = Everyone is waiting, so nobody can move.
2. System Model

A computer system contains a number of resources that processes need in order to execute.

Examples of resources:

CPU
Printer
Scanner
Memory
Files
Database locks
I/O devices

A process normally follows this sequence:

Request → Use → Release

Step 1: Request

The process requests a resource.

P1 → Request Printer

If the resource is available, the OS allocates it.

Step 2: Use

The process uses the resource.

P1 → Uses Printer

Step 3: Release

The process finishes using the resource and releases it.

P1 → Releases Printer

Basic resource usage model

Process
          │
          ↓
      Request
          │
          ↓
   Resource Available?
      /          \
    Yes           No
     ↓             ↓
   Allocate       Wait
     │
     ↓
    Use
     │
     ↓
   Release
3. Types of Resources

Resources can generally be considered as resource types.

For example:

R1 = Printer
R2 = Scanner
R3 = Disk

A resource type may have one or more instances.

Example

If a system has:

Printer = 2 instances

then two processes may use the two printers simultaneously.

For a resource with a single instance:

Printer = 1

only one process can hold it at a time.

4. Resource-Allocation Graph

A Resource-Allocation Graph (RAG) is used to represent the relationship between:

Processes
Resources
Requests
Allocations

Symbols

Circle = Process
Rectangle = Resource

Request edge

P1 → R1

means:

> P1 is requesting resource R1.

Assignment edge

R1 → P1

means:

> Resource R1 is currently allocated to P1.

Example

P1 ─────→ R2
      ↑          │
      │          ↓
      R1 ←────── P2

This represents a circular dependency.

Important point

For a system where each resource type has only one instance, a cycle in the resource-allocation graph indicates a deadlock.

When resource types have multiple instances, a cycle indicates a possibility of deadlock, but not necessarily a deadlock.
5. Deadlock Characterization

Deadlock can be characterized using the relationship between processes and resources.

A deadlock exists when there is a group of processes such that:

Every process is waiting for a resource.

That resource is held by another process in the same group.

No process can proceed until another process releases its resource.

Example

P1 holds R1 and waits for R2
P2 holds R2 and waits for R3
P3 holds R3 and waits for R1

This creates:

P1 → R2 → P2 → R3 → P3 → R1 → P1

This is a circular wait.

Because each process depends on another, none can proceed.

6. Four Necessary Conditions for Deadlock

All four conditions must exist simultaneously for a deadlock to occur.

These are:

  1. Mutual Exclusion
  2. Hold and Wait
  3. No Preemption
  4. Circular Wait
7. Condition 1 — Mutual Exclusion

Mutual Exclusion means that a resource can be used by only one process at a time.

If P1 is using a printer:

P1 → Printer

P2 cannot use the same printer at that exact time.

Example

Printer → P1
P2 → Waiting

The resource is non-shareable.

🧠 Memory:

> Mutual Exclusion = One resource, one user at a time.
8. Condition 2 — Hold and Wait

A process is holding at least one resource while waiting to obtain another resource.

Example

P1 holds Printer
P1 waits for Scanner

So:

P1
├── Holds → Printer
└── Wants → Scanner

This condition allows processes to maintain resources while waiting for additional resources.

🧠 Memory:

> Hold one → Wait for another
9. Condition 3 — No Preemption

No Preemption means a resource cannot be forcibly taken away from a process.

The process must release the resource voluntarily after completing its operation.

Example

If P1 has a printer:

P1 → Printer

the OS cannot simply take the printer away from P1 in the middle of its operation.

P1 must finish and release it.

🧠 Memory:

> No Preemption = Resource cannot be forcibly taken.
10. Condition 4 — Circular Wait

A Circular Wait exists when a set of processes form a circular chain, where each process is waiting for a resource held by the next process.

Example

P1 waits for R2
R2 held by P2

P2 waits for R3
R3 held by P3

P3 waits for R1
R1 held by P1

Graphically:

P1 → R2 → P2 → R3 → P3 → R1 → P1

This forms a cycle.

🧠 Memory:

> Circular Wait = Everyone is waiting in a circle.
11. Complete Deadlock Example

Consider:

Resources:

R1 = Printer
R2 = Scanner

Initial state:

P1 holds R1
P2 holds R2

Then:

P1 requests R2
P2 requests R1

Now:

P1 → waiting for R2 → held by P2
P2 → waiting for R1 → held by P1

Therefore:

P1 ↔ P2

Neither can proceed.

Why?

All four conditions are present:

Condition Example
Mutual Exclusion Printer/Scanner used by one process
Hold and Wait Each process holds one resource and waits for another
No Preemption Resource cannot be forcibly taken
Circular Wait P1 waits for P2, P2 waits for P1

Therefore, a deadlock occurs.

12. Four Conditions — Easy Memory
Remember:

> M → H → N → C

Mutual Exclusion
Hold and Wait
No Preemption
Circular Wait

Easy sentence:

> “My Hands Never Cross.”

My → Mutual
Hands → Hold
Never → No Preemption
Cross → Circular
3(b). Analyze Deadlock Prevention and Avoidance Techniques. Explain How Deadlocks Can Be Prevented by Eliminating the Necessary Conditions with Suitable Examples.
1. Deadlock Prevention

Deadlock prevention ensures that at least one of the four necessary conditions for deadlock is never allowed to occur.

The four conditions are:

Mutual Exclusion
Hold and Wait
No Preemption
Circular Wait

If even one condition is eliminated, deadlock cannot occur.

2. Prevention of Mutual Exclusion

Mutual exclusion cannot always be eliminated because some resources are naturally non-shareable.

However, for resources that can be shared, sharing can prevent this condition.

Example

A read-only file can be accessed by multiple processes simultaneously.

P1 ──┐
P2 ──┼──→ Read-only File
P3 ──┘

Since the resource is shareable, mutual exclusion is not required.

Limitation

Resources such as:

Printer
Certain locks
Exclusive devices

cannot normally be shared simultaneously.

Therefore, this method is not always practical.

3. Prevention of Hold and Wait

One method is to require a process to request all required resources before it begins execution.

Example

Suppose P1 needs:

Printer + Scanner

Instead of:

P1 → Gets Printer
P1 → Waits for Scanner

it must request both:

P1 → Request Printer + Scanner together

If both are available, it gets them.

If not, P1 waits without holding any resource.

Advantage

This prevents:

Hold + Wait

Disadvantage

Resources may remain unused for a long time.

4. Prevention of No Preemption

To prevent the No Preemption condition, resources may be taken away under certain circumstances.

Example

Suppose P1 holds:

R1

and requests:

R2

but R2 is unavailable.

The system can force P1 to release R1 and make P1 wait.

Later, when both resources are available, P1 can obtain them.

P1 holds R1
      ↓
Requests R2
      ↓
R2 unavailable
      ↓
Release R1
      ↓
Wait
      ↓
Get R1 + R2 together later
Important point

Preemption is practical only for resources whose state can be safely saved and restored.
5. Prevention of Circular Wait

A common technique is to impose a fixed ordering on resource types.

Suppose:

R1 < R2 < R3

Processes must request resources only in increasing order.

R1 → R2 → R3

is allowed.

But:

R3 → R1

is not allowed.

Example

If:

Printer = R1
Scanner = R2

a process must always request:

Printer → Scanner

and never:

Scanner → Printer

> Fixed order → No circle → No deadlock

6. Summary of Deadlock Prevention
Necessary Condition Prevention Method
Mutual Exclusion Share resources where possible
Hold and Wait Request all resources together
No Preemption Preempt/reclaim resources where possible
Circular Wait Impose resource ordering
7. Deadlock Avoidance

Deadlock avoidance does not permanently eliminate any condition.

Instead, the OS examines each resource request and determines whether granting it will leave the system in a safe state.

Basic idea

Process requests resource
        ↓
OS checks request
        ↓
Will system remain safe?
      /       \
    Yes        No
     ↓          ↓
 Allocate      Make process wait
8. Safe State

A system is in a safe state if there is at least one order in which all processes can finish without causing deadlock.

This order is called a safe sequence.

Example

<P1, P3, P2>

means:

P1 can finish

then P3 can finish

then P2 can finish

Therefore, the system can safely complete all processes.

9. Unsafe State

An unsafe state means the system cannot guarantee that all processes will finish without deadlock.

Important:

> Unsafe does not always mean deadlocked.

It means:

> The system has entered a state where deadlock may occur.
10. Banker's Algorithm

The most common deadlock avoidance technique is the Banker's Algorithm.

It checks whether granting a resource request maintains a safe state.

It uses:

Available
Maximum
Allocation
Need

with:

Need = Maximum − Allocation
11. Prevention vs Avoidance
Prevention Avoidance
Eliminates at least one necessary condition. Allows conditions but carefully controls allocation.
Uses fixed restrictions. Makes decisions dynamically.
Simpler conceptually. Requires information about maximum resource needs.
Example: Resource ordering. Example: Banker's Algorithm.
Easy memory

> Prevention = Break the conditions
Avoidance = Check before allocating
12. Simple Illustration

Prevention

Force:
R1 → R2 → R3

Circular Wait impossible

Avoidance

Request
  ↓
Safety check
  ↓
Safe? ── Yes → Allocate
  │
  No
  ↓
Wait
4(a). Explain the Necessary Conditions for Deadlock and Describe the Methods of Deadlock Prevention with Suitable Examples.
1. Four Necessary Conditions

A deadlock can occur only when all four conditions exist at the same time.

A. Mutual Exclusion

A resource can be assigned to only one process at a time.

Example

Printer → P1

P2 must wait.

Prevention

Where possible, make resources shareable.

Example:

Read-only file → Multiple readers
B. Hold and Wait

A process holds at least one resource while waiting for another.

Example

P1:
Holds → Printer
Waits → Scanner

Prevention

Require the process to request all required resources at once.

Request: Printer + Scanner

If both are unavailable, the process gets nothing and waits.

C. No Preemption

A resource cannot be forcibly taken from a process.

Example

P1 holds Printer
P2 requests Printer

P2 cannot forcibly take it.

Prevention

Allow the system to preempt/reclaim resources when appropriate.

For example, if a process requests a resource that is unavailable, it may be required to release resources it currently holds.

D. Circular Wait

A circular chain of waiting processes exists.

Example

P1 → R2 → P2 → R3 → P3 → R1 → P1

Prevention

Impose a strict ordering:

R1 < R2 < R3

Processes must request resources in increasing order.

Thus:

R1 → R2 → R3

is allowed, while:

R3 → R1

is prohibited.

2. Deadlock Prevention Techniques
Technique 1 — Resource Sharing

If a resource can be safely shared, allow multiple processes to use it simultaneously.

Example

Read-only file
      ↓
P1 + P2 + P3

This eliminates the need for mutual exclusion for that resource.

Technique 2 — Request All Resources at Once

A process must request all the resources it needs before beginning execution.

Example

P1 requires:

Printer + Scanner

It requests both together.

Both available → Allocate
One unavailable → Wait without holding any

This eliminates Hold and Wait.

Technique 3 — Resource Preemption

If a process cannot obtain a requested resource, the OS can make it release resources it already holds, where the resource and application semantics permit.

Example

P1:
Holds R1
Requests R2

R2 unavailable

        ↓

Release R1
        ↓
Wait

This helps eliminate No Preemption.

Technique 4 — Resource Ordering

Assign an order to resource types.

R1 < R2 < R3

A process must request:

R1 before R2
R2 before R3

This prevents circular waiting.

3. Complete Example

Consider:

P1 holds Printer and requests Scanner.
P2 holds Scanner and requests Printer.

Without prevention:

P1 → Scanner → P2
P2 → Printer → P1

Deadlock occurs.

Using resource ordering:

Suppose:

Printer = R1
Scanner = R2

Both processes must request:

R1 → R2

P2 cannot request Scanner first and then Printer.

Therefore, the circular wait is broken.

4. Prevention Summary
Condition How to Prevent
Mutual Exclusion Share resources where possible
Hold and Wait Request all resources together
No Preemption Allow resource preemption where possible
Circular Wait Impose resource ordering
🧠 Memory

> Share → All-at-once → Take-back → Order
4(b). Explain the Banker's Algorithm for Deadlock Avoidance, with its Safety and Resource-Request Algorithms.
1. Banker's Algorithm

The Banker's Algorithm is a deadlock avoidance algorithm.

It checks whether granting a process's resource request will keep the system in a safe state.

The basic idea is:

> Never make a resource allocation that could lead the system into an unsafe state.

It is called the Banker's Algorithm because it works like a bank that gives loans only when it can still satisfy all customers safely.

2. Data Structures Used

For n processes and m resource types, the Banker's Algorithm uses:

Available

Maximum

Allocation

Need
Available

Available[j] represents the number of available instances of resource type j.

Available = [3, 2, 1]

means the system currently has:

3 instances of R1
2 instances of R2
1 instance of R3
Maximum

Max[i][j] represents the maximum number of resources of type j that process Pi may need.

Allocation

Allocation[i][j] represents the number of resource instances of type j currently allocated to process Pi.

Need

Need[i][j] represents how many more resources process Pi may still require.

The formula is:

Need = Max − Allocation

Example

If:

Max = 7
Allocation = 3

then:

Need = 7 − 3 = 4
3. Important Banker's Algorithm Terms
Term Meaning
Available Currently free resources
Max Maximum possible requirement
Allocation Resources currently given
Need Resources still required
Safe State System can finish all processes safely
Unsafe State System cannot guarantee safe completion
4. Safety Algorithm

The Safety Algorithm determines whether the current system state is safe.

Step 1: Initialize

Set:

Work = Available

Create a Finish array for all processes:

Finish[i] = false

Step 2: Find a process

Find a process Pi such that:

Finish[i] == false

and

Need[i] <= Work

This means the process's remaining requirements can be satisfied using currently available resources.

Step 3: Pretend it finishes

If such a process exists, assume it gets the needed resources, finishes, and releases all resources it held.

Update:

Work = Work + Allocation[i]

Then:

Finish[i] = true

Step 4: Repeat

Repeat the process until:

All processes have Finish = true, or

No suitable process can be found.
5. Safety Algorithm Pseudocode
Work = Available

For each process Pi:
    Finish[i] = false

Find Pi such that:
    Finish[i] == false
    and Need[i] <= Work

If found:
    Work = Work + Allocation[i]
    Finish[i] = true
    repeat

If all Finish[i] == true:
    System is SAFE
Else:
    System is UNSAFE
6. Safety Algorithm — Simple Example

Suppose:

Available = 3
Process Need Allocation
P1 1 2
P2 2 1
P3 4 3

Step 1

Work = 3

P1 needs 1:

1 <= 3

So P1 can finish.

After P1 completes:

Work = 3 + 2
= 5

Step 2

P2 needs 2:

2 <= 5

P2 can finish.

Work = 5 + 1
= 6

Step 3

P3 needs 4:

4 <= 6

P3 can finish.

Therefore the safe sequence is:

<P1, P2, P3>

The system is SAFE.

7. Resource-Request Algorithm

The Resource-Request Algorithm is used when a process makes a new resource request.

Suppose process Pi requests:

Request[i]

The following steps are performed.

Step 1: Check Request Against Need

If:

Request[i] > Need[i]

the process is asking for more than its declared maximum.

Therefore:

Error

Step 2: Check Request Against Available

If:

Request[i] > Available

the required resources are currently unavailable.

Therefore:

Process must wait

Step 3: Pretend to Allocate

If:

Request[i] <= Need[i]

and

Request[i] <= Available

temporarily allocate the resources:

Available = Available − Request[i]

Allocation[i] = Allocation[i] + Request[i]

Need[i] = Need[i] − Request[i]

Step 4: Run Safety Algorithm

After the temporary allocation, the OS runs the Safety Algorithm.

If safe:
Request is granted

If unsafe:
Allocation is rolled back
Process must wait
8. Resource-Request Algorithm Pseudocode
Request[i] = resource request of Pi

if Request[i] > Need[i]
    Error

else if Request[i] > Available
    Pi must wait

else
{
    Available = Available - Request[i]

    Allocation[i] =
        Allocation[i] + Request[i]

    Need[i] =
        Need[i] - Request[i]

    if Safety Algorithm says SAFE
        Grant request
    else
    {
        Roll back allocation
        Pi must wait
    }
}
9. Simple Illustration
Process requests resources
          ↓
Request ≤ Need ?
       /       \
     No         Yes
     ↓            ↓
   Error      Request ≤ Available?
                   /       \
                 No         Yes
                 ↓           ↓
              Wait      Temporarily allocate
                              ↓
                       Run Safety Algorithm
                              ↓
                         Safe or Unsafe
                         /          \
                      Safe         Unsafe
                       ↓              ↓
                    Grant          Roll back
                    request        and wait
10. Safety vs Resource-Request Algorithm
Safety Algorithm Resource-Request Algorithm
Checks whether current state is safe. Handles a new resource request.
Uses Work and Finish. Uses Request, Available, Need, Allocation.
Finds a safe sequence. Decides whether a request can be granted.
Used after temporary allocation in request checking. First checks the validity and availability of a request.
11. Important Formula

The most important formula in Banker's Algorithm is:

Need = Max − Allocation
🧠 Remember:

> What I MAY need − What I ALREADY have = What I STILL need
12. Complete Banker's Algorithm Flow
RESOURCE REQUEST
                     │
                     ↓
            Request ≤ Need ?
               /          \
             No            Yes
             ↓              ↓
           Error      Request ≤ Available?
                           /       \
                         No         Yes
                         ↓           ↓
                       Wait      Temporary
                                 Allocation
                                    │
                                    ↓
                              Safety Algorithm
                                    │
                              ┌─────┴─────┐
                              ↓           ↓
                           SAFE        UNSAFE
                              ↓           ↓
                           Grant      Rollback
                          Request       + Wait
@Thinking