2235 ESY Unit 5
2235 ESY Unit 5
----------------------------------------------------------------------------------------------------------------
Unless and until a higher priority interrupt occurs during its execution, this process is fully
uninterrupted. As a result, the interruptions must be prioritised in a specific order. The
highest priority interrupt should be permitted to start the process, and the lower priority
interrupts must be stored in a buffer and handled later. In such an OS, interrupt management
is critical.
Because standard operating systems cannot achieve such performance, real-time operating
systems need special-purpose operating systems.
Lynx
MTS
VxWorks
MTS
Applications
Real-time operating systems (RTOS) are employed in real-time applications that must meet
strict deadlines. The following are some of the most common applications of real-time
operating systems.
Types of Real-time OS
1. Hard RTOS
All key tasks in Hard RTOS must be accomplished within the defined time frame or within
the supplied deadline. Failure to achieve the deadline would result in catastrophic failures,
such as equipment damage or even human life loss.
Example
Consider airbags and a handle in the driver’s seat, both given by automakers. When the driver
applies the brakes at a certain point, the airbags expand to protect the driver’s head from
colliding with the steering wheel. There would have been an accident if there had been even a
millisecond of delay.
Consider using online stock trading software. If someone wants to sell a specific stock, the
system must ensure that the command is carried out within a certain amount of time.
Otherwise, if the market drops suddenly, the trader may suffer a significant loss.
2. Soft RTOS
Soft RTOS allows for a few delays through the operating system. There may be a deadline
assigned to a job with this type of RTOS, but a minor delay is allowed. Cut-off dates are thus
softly handled by this type of RTOS.
Example
Both online transaction systems and livestock price quote systems employ this type of
system.
Pros of RTOS
Real-time applications are simple to design, develop, and run on the real-time
operating system.
Because real-time working structures are extremely small, they require significantly
less memory.
The maximum use of devices and systems in a real-time operating system.
Focus on apps that are already executing rather than those that are in the queue.
Because the programs are tiny, RTOS can be used in embedded systems such as
transportation.
These systems are completely error-free.
In these systems, memory allocation is best regulated.
Cons of RTOS
Real-time operating systems are difficult to design and implement due to their
complex layout principles.
Real-time operating systems are quite complex and can eat up a lot of CPU time.
----------------------------------------------------------------------------------------------------------------
Definition: Reliability is the ability of a system to perform its intended function consistently
over time, even in the presence of faults or errors. It involves features such as fault tolerance,
robust error handling, and the capacity for self-diagnosis, ensuring that the system remains
operational and effective.
3. Scalability
4. Performance
5. Predictability
Definition: Predictability is the characteristic of a system that allows for the anticipation of
its behaviour, particularly in terms of timing and task execution. It involves providing
guarantees about when tasks will start and finish, enabling developers to design applications
with confidence in meeting real-time requirements.
These definitions highlight the importance of each characteristic in the context of real-time
operating systems and their applications.
----------------------------------------------------------------------------------------------------------------
1. Task Management
2. Interrupt handling
3. Memory management
4. Exception handling
5. Task synchronization
6. Task scheduling
7. Time management
A Real-Time Operating System (RTOS) performs several critical functions to manage hardware
resources, execute tasks, and ensure timely and predictable system behaviour. Here are the main
functions of an RTOS:
1. Task Management
Task Scheduling: Determines the order and timing of task execution based on priority and
timing constraints.
Context Switching: Manages the switching of the CPU between different tasks, saving and
restoring the state as needed.
2. Inter-Task Communication
3. Synchronization
Semaphores and Mutexes: Provides tools for synchronizing access to shared resources,
preventing race conditions and ensuring data integrity.
Event Flags: Allows tasks to wait for specific events to occur, enabling coordinated
execution.
Timers: Supports precise timing operations for task scheduling and delays, enabling tasks to
execute at specific intervals.
Timeouts: Implements timeouts for waiting tasks to ensure they do not block indefinitely.
5. Resource Management
Memory Management: Allocates and deallocates memory efficiently to ensure that tasks
have the resources they need without fragmentation.
Device Management: Manages hardware resources (like I/O devices) to ensure that tasks can
interact with them in a controlled manner.
6. Interrupt Handling
Error Detection: Monitors system health and detects faults to prevent system failures.
Graceful Recovery: Implements strategies to recover from errors without compromising
system stability.
8. Configuration and Control
----------------------------------------------------------------------------------------------------------------
Types of Process
Independent process
Co-operating process
An independent process is not affected by the execution of other processes while a co-
operating process can be affected by other executing processes. Though one can think that
those processes, which are running independently, will execute very efficiently, in reality,
there are many situations when cooperative nature can be utilized for increasing
computational speed, convenience, and modularity. Inter-process communication (IPC) is a
mechanism that allows processes to communicate with each other and synchronize their
actions. The communication between these processes can be seen as a method of cooperation
between them. Processes can communicate with each other through both:
Methods of IPC
Shared Memory
Message Passing
Pipes
The Shared memory is a memory segment that multiple processes can access concurrently. It
is one of the fastest IPC methods because the processes communicate by the reading and
writing to a shared block of the memory. Unlike other IPC mechanisms that involve the more
complex synchronization and data exchange procedures shared memory provides the
straightforward way for the processes to share data.
Figure 1 below shows a basic structure of communication between processes via the shared
memory method and via the message passing method.
An operating system can implement both methods of communication. First, we will discuss
the shared memory methods of communication and then message passing. Communication
between processes using shared memory requires processes to share some variable, and it
completely depends on how the programmer will implement it. One way of communication
using shared memory can be imagined like this: Suppose process1 and process2 are executing
simultaneously, and they share some resources or use some information from another
process. Process1 generates information about certain computations or resources being used
and keeps it as a record in shared memory. When process2 needs to use the shared
information, it will check in the record stored in shared memory and take note of the
information generated by process1 and act accordingly. Processes can use shared memory for
extracting information as a record from another process as well as for delivering any specific
information to other processes.
Speed: The Shared memory IPC is much faster than other IPC methods like message
passing because processes directly read and write to the shared memory location.
Low Overhead: It eliminates the overhead associated with the message passing
where data has to be copied from the one process to another.
Flexibility: The Shared memory can be used to share complex data structures like
arrays, linked lists and matrices between the processes.
Large Data Transfers: The Shared memory is particularly useful for the transferring
large amounts of data between the processes as it avoids the need for the multiple data
copies.
Manual Clean-up: The Shared memory segments must be manually detached and
removed which can lead to the resource leaks if not done correctly.
Portability: The Shared memory IPC is platform-dependent and may not be easily
portable across the different operating systems.
Now, we will start our discussion of the communication between processes via message passing. In
this method, processes communicate with each other without using any kind of shared memory. If two
processes p1 and p2 want to communicate with each other, they proceed as follows:
Establish a communication link (if a link already exists, no need to establish it again.)
iii) Pipes
1. Unidirectional Communication:
o Pipes typically support one-way data flow, meaning data can be sent from one task to
another in a single direction. If bidirectional communication is needed, two pipes may
be used.
1. Creation:
o A pipe is created using a specific API call, which establishes the communication
channel and allocates necessary resources.
2. Writing to a Pipe:
o A sending task writes data to the pipe using a write function. If the pipe is full, the
sending task may block or return an error, depending on the configuration.
3. Reading from a Pipe:
o A receiving task reads data from the pipe using a read function. If the pipe is empty,
the receiving task may block until data becomes available or return immediately if
using non-blocking mode.
4. Data Types:
o Pipes can handle various data types, including simple data (like bytes or integers) or
more complex data structures, depending on the implementation.
Advantages of Pipes
Challenges of Pipes
Limited Size: The size of the pipe's buffer can limit the amount of data that can be sent at
once. If the buffer fills up, the sending task may be blocked or encounter errors.
Unidirectionality: Since pipes are typically unidirectional, managing bidirectional
communication may require additional pipes, increasing complexity.
----------------------------------------------------------------------------------------------------------------
In a modern computer system, the word ―multitasking‖ is employed. It’s a logical extension
of the multiprogramming system that allows numerous applications to run simultaneously.
Multitasking in an OS enables a user to execute multiple computer tasks at the same time.
Processes that hold common processing resources, such as a CPU, are known as many tasks.
The operating system remembers where you are in these jobs and lets you switch between
them without data being lost.
Although early operating systems could run multiple programs at once, multitasking was not
completely supported. As a result, a single piece of software might use the entire CPU of the
computer to complete a task. The user was unable to do other operations, such as opening and
shutting windows, because basic operating system capabilities, such as file copying, were
disabled. Because modern OS provide comprehensive multitasking, multiple programs can
run simultaneously without interfering with one another. Furthermore, many OS processes
can operate concurrently.
Pros of Multitasking OS
This OS is more suited to support several users at the same time, and multiple apps can
operate smoothly without slowing down the system.
Virtual memory
Multitasking operating systems have the best virtual memory system. Any program does not
need a long wait time to perform its tasks because of virtual memory; if this problem arises,
then those applications are shifted to virtual memory.
Good reliability
Multitasking operating systems provide multiple users more flexibility, which makes them
happier. Besides, each user can run one or more apps at the same time.
Secured memory
Time shareable
To avoid having to wait for the CPU, each task is given a specific length of time.
Background processing
Background processes can operate more efficiently under a multitasking operating system.
Most users are unaware of these background processes, although they aid the smooth
operation of other programs such as antivirus software, firewalls, and others.
A multitasking OS can manage I/O devices, RAM, hard discs, CPUs, and other computer
resources.
Users can run multiple programs at the same time, such as games, an internet browser,
Microsoft PowerPoint, Excel, and other utilities.
Cons of Multitasking OS
Processor boundation
Because of the modest pace of its processors, the system may run applications slowly, and
their reaction time may increase when processing many programs. More computing power is
necessary to solve this challenge.
Memory boundation
The computer’s performance may suffer as a result of many programs running at the same
time, as the main memory becomes overcrowded when multiple programs are loaded.
Reaction time grows since the CPU is unable to give distinct times for each program. The
usage of low-capacity RAM is the primary cause of this problem. As a result, the capacity of
the RAM can be increased to meet the requirements.
CPU heat up
In a multitasking environment, numerous processors are busier at the very same time to finish
any task; therefore, the CPU generates more heat.
----------------------------------------------------------------------------------------------------------------
Scheduling: scheduling algorithms
Task State
1. New
2. Ready
Definition: The process is ready to run but is waiting for CPU time.
Details: The process has all the resources it needs to execute and is waiting in a queue for the
scheduler to allocate CPU time. Multiple processes can be in this state simultaneously.
3. Running
Definition: The process is waiting for an event to occur or for resources to become available.
Details: This state can occur when a process needs to wait for I/O operations to complete, for
a signal from another process, or for a resource that is currently unavailable.
New to Ready: When the process is created and initialized, it moves to the ready state.
Ready to Running: The scheduler selects a process from the ready queue to execute on the
CPU.
Running to Waiting: If the process requires I/O or is waiting for an event, it moves to the
waiting state.
Running to Ready: If a higher-priority process needs to run, the current process may be pre-
empted and moved back to the ready state.
Waiting to Ready: Once the event the process is waiting for occurs, it moves back to the
ready state.
Running to Terminated: When a process finishes execution, it moves to the terminated state.
Ready to Suspended: If the system needs to manage memory more effectively, it may
suspend a ready process.
Suspended to Ready: A suspended process can be resumed and moved back to the ready
state when resources are available.
Pre-emptive scheduling is used when a process switches from the running state to the ready
state or from the waiting state to the ready state. The resources (mainly CPU cycles) are
allocated to the process for a limited amount of time and then taken away, and the process is
again placed back in the ready queue if that process still has CPU burst time remaining. That
process stays in the ready queue till it gets its next chance to execute.
----------------------------------------------------------------------------------------------------------------
Scheduling Process
Scheduling is the process of deciding which task should be executed at any point in time
based on a predefined algorithm. The logic for the scheduling is implemented in a functional
unit called the scheduler. The scheduling process is not present only in RTOS, it can be found
in one form or another even in simple ―bare-bone‖ applications.
There are many scheduling algorithms that can be used for scheduling task execution on a
CPU. They can be classified into two main types: pre-emptive scheduling algorithms and
non-pre-emptive scheduling algorithms.
Pre-emptive Scheduling
Pre-emptive scheduling allows the interruption of a currently running task, so another one
with more ―urgent‖ status can be run. The interrupted task is involuntarily moved by the
scheduler from running state to ready state. This dynamic switching between tasks that this
algorithm employs is, in fact, a form of multitasking. It requires assigning a priority level for
each task. A running task can be interrupted if a task with a higher priority enters the queue.
As an example let’s have three tasks called Task 1, Task 2 and Task 3. Task 1 has the lowest
priority and Task 3 has the highest priority. Their arrival times and execute times are listed in
the table below.
In Fig. 1 we can see that Task 1 is the first to start executing, as it is the first one to arrive (at t
= 10 μs ). Task 2 arrives at t = 40μs and since it has a higher priority, the scheduler interrupts
the execution of Task 1 and puts Task 2 into running state. Task 3 which has the highest
priority arrives at t = 60 μs. At this moment Task 2 is interrupted and Task 3 is put into
running state. As it is the highest priority task it runs until it completes at t = 100 μs. Then
Task 2 resumes its operation as the current highest priority task. Task 1 is the last to complete
is operation.
In non-pre-emptive scheduling, the scheduler has more restricted control over the tasks. It
can only start a task and then it has to wait for the task to finish or for the task to voluntarily
return the control. A running task can’t be stopped by the scheduler.
If we take the three tasks specified in the table from the previous chapter and schedule them
using a non-pre-emptive algorithm we get the behaviour shown in Fig. 2. Once started, each
task completes its operation and then the next one starts.
The non-pre-emptive scheduling can simplify the synchronization of the tasks, but that is at
the cost of increased response times to events. This reduces its practical use in complex real-
time systems.
We will now introduce some of the most popular scheduling algorithms that are used in CPU
scheduling. Not all of them are suitable for use in real-time embedded systems. Currently, the
most used algorithms in practical RTOS are non-pre-emptive scheduling, round-robin
scheduling, and pre-emptive priority scheduling.
FCFS is a non-pre-emptive scheduling algorithm that has no priority levels assigned to the
tasks. The task that arrives first into the scheduling queue (i.e. enters ready state), gets put
into the running state first and starts utilizing the CPU. It is a relatively simple scheduling
algorithm where all the tasks will get executed eventually. The response time is high as this is
a non-pre-emptive type of algorithm.
Shortest Job First (SJF)
In the shortest job first scheduling algorithm, the scheduler must obtain information about the
execution time of each task and it then schedules the one with the shortest execution time to
run next.
SJF is a non-pre-emptive algorithm, but it also has a pre-emptive version. In the pre-emptive
version of the algorithm (aka shortest remaining time) the parameter on which the scheduling
is based is the remaining execution time of a task. If a task is running it can be interrupted if
another task with shorter remaining execution time enters the queue.
A disadvantage of this algorithm is that it requires the total execution time of a task to be
known before it is run.
Priority Scheduling
Priority scheduling is one of the most popular scheduling algorithms. Each task is assigned a
priority level. The basic principle is that the task with the highest priority will be given the
opportunity to use the CPU.
In the pre-emptive version of the algorithm, a running task can be stopped if a higher priority
task enters the scheduling queue. In the non-pre-emptive version of the algorithm once a task
is started it can’t be interrupted by a higher priority task.
Of course, not all tasks can have unique priority levels and there will always be tasks that
have the same priority. Different approaches can be used for handling the scheduling of those
tasks (e.g. FCFS scheduling or round-robin scheduling).
Round-Robin Scheduling
The job with the shortest burst time will get the CPU first. The lesser the burst time, the
sooner will the process get the CPU. It is the non-pre-emptive type of scheduling.
It is the pre-emptive form of SJF. In this algorithm, the OS schedules the Job according to the
remaining time of the execution.
----------------------------------------------------------------------------------------------------------------
Resource allocation in a Real-Time Operating System (RTOS) is essential for managing the
system's resources—such as CPU time, memory, and I/O devices—effectively among
multiple tasks. Proper resource allocation ensures that tasks meet their deadlines and operate
efficiently. Here’s a detailed look at how resource allocation works in an RTOS:
1. Types of Resources:
o CPU Time: Allocating CPU cycles to tasks based on their scheduling priority and
timing requirements.
o Memory: Managing memory allocation (both static and dynamic) to ensure that each
task has the required resources without fragmentation.
o I/O Devices: Coordinating access to peripherals to avoid conflicts and ensure timely
data processing.
2. Scheduling Algorithms:
o The RTOS uses various scheduling algorithms to allocate CPU time:
Rate Monotonic Scheduling (RMS): Assigns priorities based on task
frequency; shorter period tasks are given higher priority.
Earliest Deadline First (EDF): Dynamically assigns priorities based on the
deadlines of tasks, allowing the task with the closest deadline to run first.
Fixed-Priority Scheduling: Tasks are assigned static priorities, and the
scheduler runs the highest-priority task.
3. Memory Management:
o Static Allocation: Memory is allocated at compile time; ensuring tasks have fixed
memory blocks.
o Dynamic Allocation: Memory can be allocated and deallocated at runtime, requiring
careful management to prevent fragmentation.
o Memory Pools: Pre-allocated blocks of memory for specific tasks or types of data,
improving allocation speed and reducing fragmentation.
4. Resource Reservation:
o Techniques for reserving resources for high-priority tasks to ensure they can meet
their deadlines without contention.
Interrupt handling in a Real-Time Operating System (RTOS) is a critical feature that enables
the system to respond promptly to external events. Interrupts are signals generated by
hardware or software to indicate that an event needs immediate attention, allowing the CPU
to pause its current tasks and execute specific interrupt service routines (ISRs). Here’s an
overview of how interrupt handling works in an RTOS:
1. Interrupt Sources:
o Interrupts can be generated by hardware devices (like timers, sensors, or I/O devices)
or by software events (such as exceptions or system calls).
2. Interrupt Service Routines (ISRs):
o ISRs are specialized functions designed to handle specific interrupts. When an
interrupt occurs, the current execution is paused, and the ISR corresponding to that
interrupt is executed.
3. Interrupt Vector Table:
o This is a data structure that maps interrupt sources to their corresponding ISRs. When
an interrupt is received, the RTOS uses this table to identify and call the correct ISR.
4. Prioritization:
o Many RTOS implementations support prioritization of interrupts. Higher-priority
interrupts can pre-empt lower-priority ISRs, allowing for timely handling of critical
events.
1. Interrupt Generation:
o An interrupt is triggered by a hardware event (e.g., a timer reaching zero, data arrival
from a peripheral).
2. Interrupt Acknowledgment:
o The CPU acknowledges the interrupt, allowing it to halt the execution of the current
task and prepare to service the interrupt.
3. Context Saving:
o Before executing the ISR, the current task's context (CPU registers, program counter,
etc.) is saved so that it can be restored after the ISR completes.
4. Executing the ISR:
o The RTOS calls the appropriate ISR based on the interrupt vector. The ISR performs
the necessary operations to handle the interrupt (e.g., reading data from a device).
5. Context Restoration:
o After the ISR completes, the saved context of the interrupted task is restored,
allowing it to resume execution.
6. Rescheduling:
o After returning from the ISR, the scheduler may decide if a higher-priority task needs
to run, potentially pre-empting the previously running task.
----------------------------------------------------------------------------------------------------------------
A watchdog timer is a hardware or software timer that is used to detect and recover from
malfunctions in a system. It works by monitoring the execution of tasks and resetting the
system if a task fails to operate within specified parameters.
Increased Reliability: By ensuring that the system can recover from unexpected faults, the
watchdog timer enhances the overall reliability of the system.
Failure Detection: It provides a mechanism for detecting when the system has failed or is not
operating as intended.
Automatic Recovery: The ability to reset the system or take corrective action without human
intervention reduces downtime and maintenance needs.
Safety Assurance: In critical applications (like automotive, medical, or industrial systems),
watchdog timers help ensure safety by detecting and responding to failures promptly.
The watchdog timer is a crucial feature of an RTOS that enhances system reliability and safety by
monitoring task execution and enabling automatic recovery from failures. By providing a robust
mechanism for detecting and responding to faults, it plays a vital role in ensuring the stability and
integrity of real-time applications.
----------------------------------------------------------------------------------------------------------------
What is a Semaphore?
A semaphore is a signalling mechanism that can be used to control access to shared resources
in a concurrent environment. It typically maintains a counter that indicates the number of
available resources or the status of a resource.
1. Types of Semaphores:
o Binary Semaphores: Also known as mutexes (mutual exclusion), these semaphores
can take only two values (0 and 1). They are used to ensure that only one task can
access a resource at a time.
o Counting Semaphores: These can take non-negative integer values and are used to
manage access to a pool of resources (e.g., a limited number of identical resources).
2. Task Synchronization:
o Semaphores allow tasks to synchronize their actions. A task can wait for a semaphore
to become available before proceeding, ensuring that critical sections of code are
executed safely.
Efficient Resource Management: Semaphores allow for effective control of resource access,
reducing the risk of conflicts and ensuring resource availability.
Task Coordination: They facilitate communication and synchronization between tasks,
which is essential for orderly execution in concurrent environments.
Reduced Complexity: Using semaphores can simplify the design of complex applications by
providing a clear mechanism for resource access.
Semaphores are a critical feature of an RTOS that enable effective synchronization and resource
management among tasks. By facilitating safe access to shared resources and promoting orderly
execution, semaphores play a vital role in ensuring the reliability and predictability of real-time
applications. Properly implemented, they help maintain system stability and performance while
preventing common concurrency issues.
The value of a semaphore variable in binary semaphores is either 0 or 1. The value of the
semaphore variable is initially set to 1, but if a process requests a resource, the wait() method
is invoked, and the value of this semaphore is changed from 1 to 0. When the process has
finished using the resource, the signal() method is invoked, and the value of this semaphore
variable is raised to 1. If the value of this semaphore variable is 0 at a given point in time, and
another process wants to access the same resource, it must wait for the prior process to
release the resource. Process synchronization can be performed in this manner.
Mutexes allow mutual exclusion for accessing crucial code regions in this fashion. Binary
semaphores, on the other hand, are concerned with synchronizing access to important parts.
Mutexes’ principal objective is, thus, mutual exclusion. For binary semaphores, however, it is
a result of the synchronization’s architecture.
In practice, a mutex only locks a vital area if an entity is present. Semaphores, on the other
hand, can render a vital region inaccessible even if no entities are present. It can happen
when, for example, an external precondition must be met before entities can access a key
area.
The main difference between a semaphore and a mutex is that a semaphore is a signalling
mechanism, while a mutex is a locking mechanism:
Semaphore
A variable or abstract data type that controls access to a shared resource by multiple
threads. Semaphores are used to synchronize behaviour between threads and interrupt
service routines (ISR). They are better for multiple instances of a resource.
Mutex
A mutual exclusion object that restricts access to a shared resource. Mutexes are used
to protect a shared resource from simultaneous access by multiple threads or
processes. They are better for a single shared resource.
The semaphore variable is first initialized with the total number of resources available in
counting semaphores. The wait() method is then executed anytime a process requires a
resource, and the value of a semaphore variable gets decreased by one. The process then uses
the resource, after which it calls the signal() function, which increases the value of a
semaphore variable by one. When the value of this semaphore variable reaches 0, that is,
when the process has utilised all of the resources and there are none left to be used, any other
process that wishes to consume the resources must wait for its own turn. Then we establish
the process synchronization in such a manner.
Illustration of Counting Semaphores in OS
Using the wait operation or (P) in a binary or counting semaphore will produce the same
result: the entity will wait in a queue until an access token is received. The signal operation or
(V) in a binary semaphore that has a value 1 (one), on the other hand, has no effect. The
signal operation in the very same conditions would increase the semaphore value into 2 (two)
in a counting semaphore.
There are situations where multiple processes must run in a key part at the same time. When
more than one process is required in the crucial part at the same time, counting semaphores
might be employed.
The semaphore implementation programming code is presented below, which comprises the
structure of the semaphore and the logic that can be used to accomplish the entry and exit in
the critical part.
A counting semaphore refers to a semaphore with several counter values. The value
can span a wide range of possibilities.
It is a structure that consists of a variable known as a semaphore variable, which can
accept more than two values, and a list of tasks or entities, which is nothing more than
the process or thread.
The number of processes or threads authorised inside the crucial region is the value of
the semaphore variable.
The counting semaphore’s value can range from 0 to N; wherein N is the number of
processes that are free to enter or exit the crucial area.
As previously stated, several processes or threads can access the crucial region of a
counting semaphore; hence mutual exclusion also isn’t guaranteed.
Counting semaphores assures bounded wait since numerous instances of the process
can use the shared resource at the same time. A process that enters the crucial section
must wait for the other process to enter the critical section using such a semaphore,
suggesting that no process will starve.
------------------------------------------------------------------------------------------------
Let us assume that there are three processes P1, P2 and P3. There are three different resources
R1, R2 and R3. R1 is assigned to P1, R2 is assigned to P2 and R3 is assigned to P3.
After some time, P1 demands for R1 which is being used by P2. P1 halts its execution since it
can't complete without R2. P2 also demands for R3 which is being used by P3. P2 also stops
its execution because it can't continue without R3. P3 also demands for R1 which is being
used by P1 therefore P3 also stops its execution.
In this scenario, a cycle is being formed among the three processes. None of the process is
progressing and they are all waiting. The computer becomes unresponsive since all the
processes got blocked.
Mutual Exclusion: Only one process can use a resource at any given time i.e. the
resources are non-sharable.
Hold and wait: A process is holding at least one resource at a time and is waiting to
acquire other resources held by some other process.
No pre-emption: The resource can be released by a process voluntarily i.e. after
execution of the process.
Circular Wait: A set of processes are waiting for each other in a circular fashion. For
example, let’s say there are a set of processes {P1P1,P2P2,P3P3} such that P1P1
depends on P2P2, P2P2 depends on P3P3 and P3P3 depends on P0P0. This creates a
circular relation between all these processes and they have to wait forever to be
executed.
Handling of deadlock - detection, prevention, ignoring
The first two methods are used to ensure the system never enters a deadlock.
Deadlock Prevention
This is done by restraining the ways a request can be made. Since deadlock occurs when all
the above four conditions are met, we try to prevent any one of them, thus preventing a
deadlock.
Deadlock Avoidance
When a process requests a resource, the deadlock avoidance algorithm examines the
resource-allocation state. If allocating that resource sends the system into an unsafe state, the
request is got granted.
Therefore, it requires additional information such as how many resources of each type is
required by a process. If the system enters into an unsafe state, it has to take a step back to
avoid deadlock.
We let the system fall into a deadlock and if it happens, we detect it using a detection
algorithm and try to recover.
Deadlock Ignorance
In the method, the system assumes that deadlock never occurs. Since the problem of deadlock
situation is not frequent, some systems simply ignore it. Operating systems such as UNIX and
Windows follow this approach. However, if a deadlock occurs we can reboot our system and
the deadlock is resolved automatically.
----------------------------------------------------------------------------------------------------------------
Deadlock Prevention
1. Mutual Exclusion
Mutual section from the resource point of view is the fact that a resource can never be used
by more than one process simultaneously which is fair enough but that is the main reason
behind the deadlock. If a resource could have been used by more than one process at the same
time then the process would have never been waiting for any resource.
However, if we can be able to violate resources behaving in the mutually exclusive manner
then the deadlock can be prevented.
Spooling
For a device like printer, spooling can work. There is a memory associated with the printer
which stores jobs from each of the process into it. Later, Printer collects all the jobs and
prints each one of them according to FCFS. By using this mechanism, the process doesn't
have to wait for the printer and it can continue whatever it was doing. Later, it collects the
output when it is produced.
Although, Spooling can be an effective approach to violate mutual exclusion but it suffers
from two kinds of problems.
We cannot force a resource to be used by more than one process at the same time since it will
not be fair enough and some serious problems may arise in the performance. Therefore, we
cannot violate mutual exclusion for a process practically.
Hold and wait condition lies when a process holds a resource and waiting for some other
resource to complete its task. Deadlock occurs because there can be more than one process
which are holding one resource and waiting for other in the cyclic order.
However, we have to find out some mechanism by which a process either doesn't hold any
resource or doesn't wait. That means, a process must be assigned all the necessary resources
before the execution starts. A process must not wait for any resource once the execution has
been started.
!(Hold and wait) = !hold or !wait (negation of hold and wait is, either you don't hold or
you don't wait)
This can be implemented practically if a process declares all the resources initially. However,
this sounds very practical but can't be done in the computer system because a process can't
determine necessary resources initially.
Process is the set of instructions which are executed by the CPU. Each of the instruction may
demand multiple resources at the multiple times. The need cannot be fixed by the OS.
3. No Pre-emption
Deadlock arises due to the fact that a process can't be stopped once it starts. However, if we
take the resource away from the process which is causing deadlock then we can prevent
deadlock.
This is not a good approach at all since if we take a resource away which is being used by the
process then all the work which it has done till now can become inconsistent.
Consider a printer is being used by any process. If we take the printer away from that process
and assign it to some other process then all the data which has been printed can become
inconsistent and ineffective and also the fact that the process can't start printing again from
where it has left which causes performance inefficiency.
4. Circular Wait
To violate circular wait, we can assign a priority number to each of the resource. A process
can't request for a lesser priority resource. This ensures that not a single process can request a
resource which is being utilized by some other process and no cycle will be formed.
Among all the methods, violating Circular wait is the only approach that can be implemented
practically.
Deadlock avoidance
In deadlock avoidance, the request for any resource will be granted if the resulting state of the
system doesn't cause deadlock in the system. The state of the system will continuously be
checked for safe and unsafe states.
In order to avoid deadlocks, the process must tell OS, the maximum number of resources a
process can request to complete its execution.
The simplest and most useful approach states that the process should declare the maximum
number of resources of each type it may ever need. The Deadlock avoidance algorithm
examines the resource allocations so that there can never be a circular wait condition.
----------------------------------------------------------------------------------------------------------------
The OS does not use any mechanisms to avoid or prevent deadlocks in this approach. As a
result, the system predicts that the deadlock will occur. The OS periodically scans the system
for any deadlocks in order to avoid them. If any deadlocks are discovered, the OS will
attempt to restore the system using several ways.
The OS’s primary responsibility is to detect deadlocks. With the help of the resource
allocation graph, the OS can detect deadlocks.
For Resource
We can take one of the resources from the resource owner (process) and give it to another
process in the hopes that it will finish the execution and release the resource sooner.
Choosing a resource that will be snatched will be challenging.
To reach the deadlock state, the system happens to go through several states. The operating
system has the ability to restore the system to a previous safe state. The OS must implement
check pointing at each state for this to work.
When we reach a deadlock, we must reverse all allocations and return to the prior safe state.
For Process
Kill a process
Our problem can be solved by killing a process; however, the bigger issue is deciding which
process to kill. A process that has done the least amount of work till now is usually killed by
the operating system.
This is not a persuasive strategy, but it may be used if the problem becomes extremely
serious. Killing all processes will result in system inefficiencies because all processes will
have to start over.
----------------------------------------------------------------------------------------------------------------
Causes of Starvation
1. Priority Scheduling:
o In priority-based scheduling, if high-priority tasks are continuously arriving, lower-
priority tasks may never get CPU time, leading to starvation.
2. Resource Contention:
o When multiple tasks compete for limited resources (e.g., semaphores, memory), some
tasks may be indefinitely postponed if they cannot acquire the necessary resources.
3. Long-Running High-Priority Tasks:
o If a high-priority task runs for an extended period without yielding control, it can
prevent lower-priority tasks from executing, resulting in starvation.
4. Improper Resource Management:
o Inefficient management of resources, such as locks and semaphores, can cause some
tasks to wait indefinitely while others proceed.
Consequences of Starvation
Missed Deadlines: Tasks that experience starvation may miss critical deadlines, undermining
the reliability of the system.
Degraded Performance: Overall system performance can be adversely affected if certain
tasks are unable to execute.
System Unresponsiveness: In interactive systems, starvation can lead to a lack of
responsiveness, frustrating users and degrading user experience.
Prevention Strategies
Conclusion
----------------------------------------------------------------------------------------------------------------