0% found this document useful (0 votes)
184 views48 pages

Unit - Ii Process Management, Synchronization and Threads

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
184 views48 pages

Unit - Ii Process Management, Synchronization and Threads

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

UNIT - II

PROCESS MANAGEMENT, SYNCHRONIZATION AND THREADS


1.Process
1.1. Process States or Process life cycle
1.2. Process Control Block
2. Process Scheduling
2.1. Scheduling Criteria
2.1.1. CPU Utilization
2.1.2. Through put
2.1.3. Waiting Time
2.1.4. Response Time
2.1.5. Turnaround Time
2.2. Scheduling Queues
2.3. Types of Schedulers
2.3.1. Long term Scheduling algorithms
2.3.2. Short term Scheduling algorithms
2.3.3. Medium term Scheduling algorithms
2.4. Context Switch
3. CPU scheduling Algorithms
3.1. FCFS
3.2. SJF
3.3. Priority
3.4. Round Robin
3.5. Multi Level Queue Scheduling
4. Inter Process Communication
4.1. Critical Section Problem
4.2. Critical Section Problem Solution Requirements
4.3. Peterson's Solution
5. Synchronization Hardware
5.1. Test and Set()
5.2. Swap()
6. Semaphores
7. Classical Problems of Synchronization
7.1. Bounded buffer Problem
7.2. Readers - Writers Problem
7.3. Dining - Philosophers Problem
8. Monitors
9. Introduction to Threads
10. Previous Examination Questions
10.1. Review Questions
OPERATING SYSTEM

Unit 2 : The Process

A process is a program in execution. A process is different from a program. A


program is a passive entity whereas a process is an active entity. A program is
also known as the text section. A process includes the current activity, as
represented by the value of the program counter and the contents of the
processor’s register. In addition, a process generally includes the process stack,
which contains temporary data (such as method parameters, return address, and
local variables), and a data section, which contains global variables.

PROCESS STATE
The state of a process is defined in part by the current activity of that process.
Each process may be in one of the following states:

Diagram of Process State


• New:
The process is being created.
• Ready:
The process is waiting to be allocated to a processor. Processor comes to
this state immediately after it is created. All ready processes (kept in
queue) keeps waiting for CPU time to be allocated by operating system in
order to run. A program called scheduler which is a part of operating
system, pick-ups one ready process for execution by passing a control to it.
• Running:
Instructions are being executed. When a process gets a control from CPU plus other resources, it starts
executing. The running process may require some I/O during execution. Depending on the particular
scheduling policy of operating system, it may pass its control back to that process or it
(operating system) may schedule another process if one is ready to run.

• Waiting:
A suspended process lacks some resource other than the CPU. Such processes are normally not
considered for execution until the related suspending conditions is fulfilled. The running process become
suspended by invoking I/O routines whose result it needs in order to proceed.

• Terminated:
When the process finally stops. A process terminates when it finishes executing its last statement. At that
point in time, the process may return some data to its parent process. Sometimes there are additional
circumstances when termination occurs. A process can cause the termination of another process via an
appropriate system call.

PROCESS CONTROL BLOCK (PCB)


The operating system groups all information that it needs about a particular process into a data structure
called a Process Control Block (PCB). It simply serves as the storage for any information for processes.
When a process is created, the operating system creates a corresponding PCB and when it terminates, its
PCB is released to the pool of free memory locations from which new PCBs are drawn. A process is
eligible to compete for system resources only when it has an active PCB associated with it. A PCB is
implemented as a record containing many pieces of information associated with a specific process,
including:

• Identifier or process number :A unique identifier associated with each process, to distinguish it
from all other processes.
• Process state: The state may be new, ready, running, waiting or terminated.
• Priority:Priority level relative to other process.
• Program counter: The counter indicates the address of the next instruction to be executed for
this process.
• Context data: These are data that are present in registers in the process while the process is
executing.
• CPU registers: They include accumulator, general purpose registers, index registers etc.
Whenever a processor switches over from one process to another process, information about
current status of the old process is saved in the register along with the program counter so that
the process be allowed to continue correctly afterwards.
• CPU-scheduling information: This information includes a process priority, pointers to
scheduling queues, and any other scheduling parameters.

• Memory-management Information: This information may include information as the value of


the base and limit registers, the page tables, or the segment tables, depending on the memory
system used by the operating system.

• Accounting information: This information includes the amount of CPU and real time used, time
limits, account numbers, job or process numbers and so on.

• I/O status information: The information includes the list of I/O devices allocated to this
process, a list of open files and so on.

PROCESSOR SCHEDULING
Scheduling is a fundamental operating system function. All computer resources are scheduled
before use. Since CPU is one of the primary computer resources, its scheduling is central to operating
system design. Scheduling refers to a set of policies and mechanisms supported by operating system that
controls the order in which the work to be done is completed. A scheduler is an operating system
program (module) that selects the next job to be admitted for execution. The main objective of
scheduling is to increase CPU utilization and higher throughput. Throughput is the amount of work
accomplished in a given time interval. CPU scheduling is the basis of operating system which supports
multiprogramming concepts. This mechanism improves the overall efficiency of the computer system by
getting more work done in less time.

Scheduling Criteria:

Different CPU - scheduling algorithms have different properties, and the choice of choosing which
algorithm to use in a particular situation is done by comparing these algorithms based on some criteria.
The criteria include the following:
• CPU utilization: We want to keep the CPU as busy as possible in all the time.
• Throughput: The number of processes that are completed per time unit, called throughput. For
long processes, this rate may be one process per hour; for short transactions, it may be ten
processes per second.
• Turnaround time: How much time it takes to execute a process. The interval from the time of
submission of a process to the time of completion is the turnaround time. Turnaround time is the
sum of the periods spent waiting to get into memory, waiting in the ready queue, executing on the
CPU , and doing I/O .
• Waiting time: The time that a process spends on waiting in the ready queue is called wating
time. Waiting time is the sum of the periods spent waiting in the ready queue.
• Response time: The time from the submission of a request until the first response is produced
this measure, called response time, is the time it takes to start responding, not the time it takes to
output the response.

It is desirable to maximize CPU utilization and throughput and to minimize turnaround time, waiting
time, and response time.
Scheduling Queues:
As processes enter the system, they are put into a job queue that consists of all processes in the system.
The processes that are residing in main memory and are ready and waiting to execute are kept on a list
called the ready queue. This queue is generally stored as a linked list. A ready-queue header contains
pointers to the first and final PCB s in the list. Each PCB includes a pointer field
that points to the next PCB in the ready queue.

The system also includes other queues. When a process is allocated the CPU , it executes for a while and
eventually quits, is interrupted, or waits for the occurrence of a particular event, such as the completion
of an I/O request. Suppose the process makes an I/O request to a shared device, such as a disk. Since
there are many processes in the system, the disk may be busy with the I/O request of some other process.
The process therefore may have to wait for the disk. The list of processes waiting for a particular I/O
device is called a device queue. Each device has its own device queue.

A common representation of process scheduling is a queueing diagram, such as that in Figure 3.7. Each
rectangular box represents a queue. Two types of queues are present: the ready queue and a set of device
queues. The circles represent the resources that serve the queues, and the arrows indicate the flow of
processes in the system. A new process is initially put in the ready queue. It waits there until it is selected
for execution, or is dispatched. Once the process is allocated the CPU and is executing, one of several
events could occur:

• The process could issue an I/O request and then be placed in an I/O queue.
• The process could create a new subprocess and wait for the subprocess’s termination.
• The process could be removed forcibly from the interrupt, and be put back in the ready queue.
CPU , as a result of an

In the first two cases, the process eventually switches from the waiting state to the ready state and is then
put back in the ready queue. A process continues this cycle until it terminates, at which time it is
removed from all queues and has its PCB and resources deallocated.

Types of Schedulers

• Long term schedulers


• Medium term schedulers
• Short term schedulers
Long-term schedulers:

This is also called job scheduler. This determines which job shall be admitted for
immediate processing. There are always more processes than it can be executed
by the CPU. These processes are kept in large storage devices like disk for later
processing. The long term scheduler selects processes from this pool and loads
them into memory. In memory these processes belong to a ready queue. The
short term scheduler (also called the CPU scheduler) selects from among the
processes in memory which are ready to execute and assigns the CPU to one of
them. The long term scheduler executes less frequently. The long-term scheduler
controls the degree of multiprogramming – the number of processes in memory. If
the degree of multiprogramming is stable, then the average rate of process
creation must be equal to the average departure rate of processes leaving the
system. Thus, the long-term scheduler may need to be invoked only when a
process leaves the system. Because of longer time taken by CPU during execution,
the long term scheduler can afford to take more time to decide which process
should be selected for execution.

It may also be very important that the long-term scheduler should take a careful
selection of processes, i.e. processes should be a combination of CPU and I/O
bound types. Generally, most processes can be put into any of the two categories:
CPU bound or I/O bound. If all processes are I/O bound, the ready queue will
always be empty and the short-term scheduler will have nothing to do. If all
processes are CPU bound, no process will be waiting for I/O operation and again
the system will be unbalanced. Therefore, the long-term scheduler provides good
performance by selecting a combination of CPU bound and I/O bound processes.

Medium-term schedulers:

Most of the processes require some I/O operation. In that case, it may become
suspended for I/O operation after running a while. It is beneficial to remove these
process (suspended) from main memory to hard disk to make room for other
processes. At some later time these process can be reloaded into memory and
continued where from it was left earlier. Saving of the suspended process is said
to be swapped out or rolled out. The process is swapped in and swapped out by
the medium term scheduler.

The medium term scheduler has nothing to do with the suspended processes. But
the moment the suspending condition is fulfilled, the medium term scheduler get
activated to allocate the memory and swapped in the process and make it ready
for execution. The medium-term scheduler is also helpful for reducing the degree
of multiprogramming, when the long term-term scheduler is absent or minimal.

(fig: long-term scheduler, medium-term scheduler, short-term scheduler)

Short-term scheduler:

This is also called CPU scheduler. When ever the CPU becomes idle, the operating
system must select one of the processes in the ready queue to be executed. The
selection process is carried out by the short-term scheduler. It allocates processes
belonging to ready queue to CPU for immediate processing. It’s main objective is
to maximize CPU utilization. Compared to the other two schedulers this is more
frequent. It must select a new process for execution quite often because a CPU
executes a process only for few milliseconds before it goes for I/O operation. Often
the short term scheduler executes at least once in every 10 milliseconds. If it
takes 1 millisecond to decide to execute a process for 10 milliseconds, the
1/(10+1) = 9% of the CPU is being wasted simply for scheduling the work.
Therefore. it must be very fast.
Context Switch (or) Process Switch:
When a CPU is executing a process, if that process get interrupted or I/O wait then the CPU is going
switches from the current process to another process which is waiting for burst time. In this context
switch mechanism system stores and restoring the state (context) of a process or thread so that execution
can be resumed from the same point at a later time. This enables multiple processes or multiple
programs to share a single CPU and is an essential feature of a multitasking operating system.

When the scheduler switches the CPU from executing one process to execute another, the context
switcher saves the content of all processor registers for the process being removed from the CPU, in its
process descriptor. The context of a process is represented in the process control block of a process.
Content switching times are highly dependent on hardware support. When the process is switched, the
following information is stored in the respective process control block.
 Program Counter
 Scheduling Information
 Base and limit register value
 Currently used register
 Changed State
 I/O State
 Accounting
Scheduling Algorithms

CPU scheduling deals with the problem of deciding which of the processes in the
ready queue is to be allocated the CPU. There are several scheduling algorithms
exists. A major division among scheduling algorithms is that whether they support
pre-emptive or non-preemptive scheduling discipline. A scheduling discipline
is non-preemptive if once a process has been given the CPU, the CPU cannot be
taken away from that process. A scheduling discipline is pre-emptive if the CPU
can be taken away. Preemptive scheduling is more useful in high priority process
which requires immediate response. In non-preemptive systems, jobs are made to
wait by longer jobs, but the treatment of all processes is fairer. The decision
whether to schedule preemptive or not depends on the environment and the type
of application most likely to be supported by a given operating system.

First-Come-First-Served Scheduling:

This is one of the simplest scheduling algorithm. With this scheme, the process
that requests the CPU first is allocated the CPU first. The implementation of the
FCFS policy is easily managed with a FIFO queue. When a process enters the
ready queue, its PCB is linked onto the tail of the queue. When the CPU is free, it
is allocated to the process at the head of the queue. The running process is then
removed from the queue.

A FCFS scheduling is non preemptive which usually results in poor performance.


As a consequence of non preemption, there is a low rate of component utilization
and system throughput. Short jobs may suffer considerable turnaround delays and
waiting times when CPU has been allocated to longer jobs.
Consider the following two processes:
Process Execution time
P1 20
P2 4

P1 P2

0 20 24
If both processes P1 and P2 arrive in order P1 -P2 in quick succession, the
turnaround times are 20 and 24 units of time respectively (P2 must wait for P1 to
complete) thus giving an average of 22 (20+24)/2) units of time. The
corresponding waiting times are 0 and 20 units of time with average of 1 0 time
units.

P2 P1

0 4 24

However, when the same processes arrive in P2-P 1 order, the turn around times
are 4 and 24 units of time respectively giving an average of 14 (4+24)/2) units of
time and the average waiting time is(0+4)/2)=2. This is a substantial reduction.
This shows how short jobs may be delayed in FCFS scheduling algorithm.
The FCFS scheduling algorithm is non preemptive. Once the CPU has been
allocated to a process, that process keeps the CPU until it releases the CPU, either
by terminating or by requesting I/O. The FCFS algorithm is particularly
troublesome for time-sharing, where each user needs to get a share of the CPU at
regular intervals.

Shortest-Job-First Scheduling:

A different approach to CPU scheduling is the Shortest-Job-First where the


scheduling of a job or a process is done on the basis of its having shortest next
CPU burst (execution time). When the CPU is available, it is assigned to the
process that has the smallest next CPU burst. If two processes have the same
length next CPU burst, FCFS scheduling is used to break the tie.
Consider the following set processes:
Process Execution time
P1 5
P2 10
P3 8
P4 3
P4  P1  P3  P2 

0 3 8 16 26

Using SJF scheduling, these processes would be scheduled in the P4 - P1 - P3 - P2


order. Waiting time is 0 + 3 + 8 + 16 / 4 = 27/4 = 6.75 units of time. If we were
using the FCFS scheduling then the average waiting time will be = (0 + 5 + 15 +
23)/4 = 43/4 = 10.75 units of time.

The SJF scheduling algorithm is provably optimal, in that it gives the minimum
average waiting time for a given set of processes. By moving a short process
before a long one, the waiting time of the short process decreases more than it
increases the waiting time of the long process. Consequently, the average waiting
time decreases.

Although the SJF algorithm is optimal, it cannot be implemented at the level of


shot-term CPU scheduling. There is no way to know the length of the next CPU
burst. SJF scheduling is used frequently in long-term scheduling. For long-term
scheduling in a batch system, we can use as the length the process time limit that
a user specifies when he submits the job.

SJF may be implemented in either non-preemptive or preemptive varieties. When


a new process arrives at the ready queue with a shorter next CPU burst than what
is left of the currently executing process, then a preemptive SJF algorithm will
preempt the currently executing process, whereas a non-preemptive SJF algorithm
will allow the currently running process to finish its CPU burst. Preemptive SJF
scheduling is also called shortest-remaining-time-first scheduling.

Consider the following processes:

Process Arrival Time Burst Time

P1 0 8

P2 1 4
P3 2 9

P4 3 5

P1  P2  P4  P1  P3 

0 1 5 10 17 26

Process P1 is started at time 0, since it is the only process in the queue. Process
P2 arrives at time 1. The remaining time for process P1 is larger than the time
required by P2, so P1 is preempted, and P2 is scheduled. The average waiting time
for this example is

(( 10 – 1 ) + ( 1 – 1 ) + ( 17 – 2 ) + ( 5 – 3 )) / 4 = 26 / 4 = 6.5. But a non-


preemptive SJF scheduling would result in an average waiting time of 7.75.

Priority Scheduling:

A priority is associated with each process and the scheduler always picks up the
highest priority process for execution from the ready queue. Equal priority
processes are scheduled in FCFS order. An SJF algorithm is simply a priority
algorithm where the priority is the inverse of the next CPU burst. The larger the
CPU burst, the lower the priority, and vice versa. The level of priority may be
determined on the basis of resource requirements, processes characteristics and
its run time behavior.

Priority scheduling can be either preemptive or non-preemptive. When a process


arrives at the ready queue, its priority is compared with the currently running
process. A preemptive priority-scheduling algorithm will preempt the CPU if the
priority of the newly arrived process is higher than the priority of the currently
running process. A non-preemptive priority-scheduling algorithm will simply put
the new process at the head of the ready queue.

A major problem with priority-scheduling algorithms in indefinite blocking (or


starvation). A priority-scheduling algorithm can leave some low-priority
processes waiting indefinitely for the CPU. In a heavily loaded computer system, a
steady stream of higher-priority processes can prevent a low-priority process from
ever getting the CPU. In general, completion of a process within finite time cannot
be guaranteed with this scheduling algorithm. A solution to the problem of
indefinite blockage of low-priority processes is aging. Aging is a technique of
gradually increasing the priority of processes that wait in the system for a long
time. Eventually, the older processes attain high priority and are ensured of
completion in a finite time.

Round-Robin Scheduling (RR):

This is one of the oldest, simplest and widely used algorithm. The round-robin
scheduling algorithm is primarily used in a time-sharing and a multi-user system
where the primary requirement is to provide reasonably good response times and
in general to share the system fairly among all system users. It is similar to FCFS
scheduling, but preemption is added to switch between processes. A small unit of
time, called a time quantum (or time slice), is defined. A time quantum is
generally from 10 to 100 milliseconds. The ready queue is treated as a circular
queue. The CPU scheduler goes around the ready queue, allocating the CPU to
each process for a time interval of up to 1 time quantum.

Each process is allocated a small time-slice (from 10-100 millisecond) while it is


running. No process can run for more than one time slice when there are others
waiting in the ready queue. If a process needs more CPU time to complete after
exhausting one time slice, it goes to the end of ready queue to await the next
allocation. Otherwise, if the running process releases a control to operating system
voluntarily due to I/O request or termination, another process is scheduled to run.

Completed job
          
CPU
X  Z  Y X

Preemption

(Fig: Round Robin Scheduling)


Round robin scheduling utilizes the system resources in an equitable manner.
Small process may be executed in a single time-slice giving good response time
whereas long processes may require several time slices and thus be forced to pass
through ready queue a few times before completion.
Consider the following processes:
Process Burst time/Execution time
P1 25
P2 5
P3 5

If we use a time-slice of 5 units of time, then P1 gets the first 5 units of time.
Since it requires another 20 units of time, it is pre-empted after the first time slice
and the CPU is given to the next process i.e. P2. Since P2 just needs 5 units of
time, it terminates as time-slice expires. The CPU is then given to the next process
P3. Once each process has received one time slice, the CPU is returned to P1 for
an additional time-slice. Thus the resulting round robin schedule is:

P1  P2  P3  P1  P1  P1  P1 

0 5 10 15 20 25 30 35

Implementation of round robin scheduling requires the support of a dedicated


timer. The timer is usually set to interrupt the operating system wherever a time
slice expires and thus force the scheduler to be involved. Processing the interrupt
to switch the CPU to another process requires saving all the registers for the old
process and then loading the registers for the new process. This task is known as
context switching. Whenever the running process surrenders control to the
operating system before expiration of its time-slice, the scheduler is again invoked
to dispatch a new process to CPU.
Multiple-Level-Queue (MLQ) Scheduling:

In MLQ, processes are classified into different groups. For example, interactive
processes (foreground) and batch processes (background) could be considered as
two types of processes because of their different response time requirements,
scheduling needs and priorities.

A multi-level-queue scheduling algorithm partitions the ready queue into several


separate queues. Processes are permanently assigned to each queue, usually
based upon properties such as memory size or process type. Each queue has its
own scheduling algorithm. The interactive queue might be scheduling by a round-
robin algorithm while batch queue follows FCFS.

As an example of multiple-level-queues scheduling one simple approach to


partitioning of the ready queue into system processes, interactive processes and
batch processes which creates a three ready queues.

System Process 
High priority
Scheduler
 

Interactive Process 
Round Robin Switch 
CPU 
Scheduler

First Cum
Batch Process 
First Serve

(fig : Multiple-Level-Queue Scheduling)

In addition, there must be scheduling among the queues. There are different
possibilities to manage queues. One possibility is to assign a time slice to each
queue, which it can schedule among different processes in its queue. Foreground
processes can be assigned 80% of CPU whereas background processes are given
20% of the CPU time.

The second possibility is to execute the high priority queue first. For example, no
process in the batch queue could run unless the queue for system processes and
interactive processes were all empty. If an interactive process entered the ready
queue while a batch process is running, the batch process would be pre-empted.

Interprocess Communication

Processes executing concurrently in the operating system may be either


independent processes or cooperating processes.

A process is independent if it cannot affect or be affected by the other processes


executing in the system. Any process that does not share data with any other
process is independent. A process is cooperating if it can affect or be affected by
the other processes executing in the system. Any process that shares data with
other process is a cooperating process.

Reasons for providing an environment that allows process cooperation:

• Information Sharing: Since several users may be interested in the same


piece of information, we must provide an environment to allow concurrent
access to such information.

• Computation Speedup: If we want a particular task to run faster, we must


break it into subtasks, each of which will be executing in parallel with the
others.

• Modularity: We may want to construct the system in a modular fashion,


dividing the system functions into separate processes or threads.

• Convenience: Even an individual user may work on may tasks at the same
time. For instance, a user may be editing, printing, and compiling in parallel.
Cooperating processes require an interprocess communication (IPC) mechanism
that will allow them to exchange data and information. Inter Process
Communication is a capability supported by operating system that allows one
process to communicate with another process. The processes can be running on
the same computer or on different computers connected through a network. IPC
enables one application to control another application, and for several applications
to share the same data without interfering with one another.

• Critical Resource

It is a resource shared with constraints on its use(e.g., memory, files,


printers, etc)

• Critical Section

It is code that accesses a critical resource.

• Mutual Exclusion

At most one process may be executing a critical section with respect to


a particular critical resource simultaneously.

There are two fundamental models of interprocess communication:

• Shared Memory

In the shared-memory model, a region of memory that is shared by


cooperating processes is established. Processes can then exchange
information by reading and writing data to the shared region.

• Message Passing

In the message-passing model, communication takes place by means of


messages exchanged between the cooperating processes.
OPERATING SYSTEM

Unit 3 : Process Coordination

Basic Concepts of Concurrency:


A concurrent program specifies two or more sequential programs (a sequential
program specifies sequential execution of a list of statements) that may be
executed concurrently as parallel processes. For example, an airline reservation
system that involves processing transactions from many terminals has a natural
specifications as a concurrent program in which each terminal is controlled by its
own sequential process. Even when processes are not executed simultaneously, it
is often easier to structure as a collection of cooperating sequential processes
rather than as a single sequential program.

The operating system consists of a collection of such processes which are basically
two types:
• Operating system processes : Those that execute system code.
• User processes : Those that execute user's code.

A simple batch operating system can be viewed as 3 processes -a reader process,


an executor process and a printer process. The reader reads cards from card
reader and places card images in an input buffer. The executor process reads card
images from input buffer and performs the specified computation and store the
result in an output buffer. The printer process retrieves the data from the output
buffer and writes them to a printer Concurrent processing is the basis of operating
system which supports multiprogramming.

The operating system supports concurrent execution of a program without


necessarily supporting elaborate form of memory and file management. This form
of operation is also known as multitasking. Multiprogramming is a more general
concept in operating system that supports memory management and file
management features, in addition to supporting concurrent execution of programs.
Basic Concepts of Interprocess Communication and Synchronization:

In order to cooperate, concurrently executing processes must communicate and


synchronize. Interprocess communication is based on the use of shared
variables (variables that can be referenced by more than one process) or
message passing.

Synchronization is often necessary when processes communicate. Processes are


executed with unpredictable speeds. Yet to communicate one process must
perform some action such as setting the value of a variable or sending a message
that the other detects. This only works if the events perform an action or detect an
action are constrained to happen in that order. Thus one can view synchronization
as a set of constraints on the ordering of events. The programmer employs a
synchronization mechanism to delay execution of a process in order to satisfy such
constraints.

To make this concept more clear, consider the batch operating system again. A
shared buffer is used for communication between the reader process and the
executor process. These processes must be synchronized so that, for example, the
executor process never attempts to read data from the input if the buffer is
empty.

Race Condition:
Processes that are working together often share some common storage that one
can read and write. The shared storage may be in main memory or it may be a
shared file. Processes frequently need to communicate with other processes. When
a user wants to read from a file, it must tell the file process what it wants, then
the file process has to inform the disk process to read the required block.

When a process wants to print a file, it enters the file name in a special spooler
directory. Another process, the printer process, periodically checks to see if
there are any files to be printed, and if there are it prints them and then removes
their names from the directory.
Imagine that the spooler directory has a large number of slots, numbered 0, 1, 2,
…, each one capable of holding a file name. Also imagine that there are two shared
variables, out, which points to the next file to be printed, and in, which points to
the next free slot in the directory and these are available to all processes. At a
certain instant, slot 0 to 3 are empty and slots 4 to 6 are full. More or less
simultaneously, process A and B decided to queue a file for printing.

Spooler directory

4 abc
out=4 

5 prog.c

in = 7 
Process A  6 prog.n

Process B 

Process A reads in and stores the value 7 in a local variable called


next_free_slot. Just then the CPU decides that process A has run long enough,
so it switches to process B. Process B also reads in and also gets a 7 so stores the
name of its file in slot 7 and updates in to be an 8. When process A runs again,
starting from the place it left off, it finds a 7 in next_free_slot and writes its file
name in slot 7, by erasing the name that process B just put there and then sets in
to 8. Situations like this, where two or more processes are reading or writing some
shared data and the final result depends on who runs precisely when, are called
race conditions.
Serialization (To avoid concurrency related problem)
Make an operating system not to perform several tasks in parallel.
Two strategies to serializing processes in a multitasking environment:
• The Scheduler can be disabled
• A Protocol can be introduced
The Scheduler can be disabled
Scheduler can be disabled for a short period of time, to prevent control being
given to another process during a critical action like modifying shared data. This
will be inefficient on multiprocessor machines, since all other processors have to
be halted every time one wishes to execute a critical section.

A Protocol can be introduced


A protocol can be introduced which all programs sharing data must obey. The
protocol ensures that processes have to queue up to gain access to shared data.

The Critical-Section Problem:


Consider a system consisting of n processes. Each process has a segment of code
called critical section, in which the process may be changing common variables,
updating a table, writing a file, and so on. When one process is executing in its
critical section, no other process is to be allowed to execute in its critical section.
That is, no two processes are executing in their critical sections at the same time.
The section of code in a process that request permission to enter into its critical
section is called entry section and the critical section may be followed by an exit
section. The remaining code is the remainder section.

When one process is executing in its critical section, no other process is to be


executed in its critical section. Thus, the execution of critical sections by the
processes is mutually exclusive in time.
Do
{
Entry Section - Section of code that request permission to
enter its critical section.
Critical Section - It is a part of code in which it is necessary to
have exclusive access to shared data.
Exit Section - Code for tasks just after exiting from the
critical section.
Remainder Section - The remaining code.

} while (TRUE);

Fig: General structure of a typical process

A solution to the critical-section problem must satisfy the following three


requirements:

o Mutual Exclusion: If process Pi is executing in its critical section, then no


other processes can be executing in their critical sections.

o Progress: If no process is executing in its critical section and some


processes wish to enter their critical sections, then only those processes that
are not executing in their remainder section can participate in the decision
on which will enter its critical section next, and this selection can not be
postponed indefinitely.

o Bounded Waiting: There exists a bound on the number of times that 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.
Mutual Exclusion:
Processes frequently need to communicate with other processes. When a user
wants to read from a file, it must tell the file process what it wants, then the file
process has to inform the disk process to read the required block.

Processes that are working together often share some common storage that one
can read and write. The shared storage may be in main memory or it may be a
shared file. Each process has segment of code, called a critical section, which
accesses shared memory or files. The key issue involving shared memory or
shared files is to find way to prohibit more than one process from reading and
writing the shared data at the same time. What we need is mutual exclusion -
some way of making sure that if one process is executing in its critical section, the
other processes will be excluded from doing the same thing.

An algorithm to support mutual exclusion. This is applicable for two processes


only.

Module Mutex
var
P1busy, P2busy : boolean;
Process P1
begin
while true do
begin
P1busy :=true;
While P2busy do {keep testing};
critical.-,section;
P1busy:=false;
Other_P1busy_Processing
end {while}
end; {P1}

Process P2
begin
while true do
begin
P2busy :=true;
While P1busy do {keep testing};
critical.-,section;
P2busy:=false;
Other_P2busy_Processing
end {while}
end; {P2}

{Parent process}
begin (mutex)
P1busy:=false;
P2busy:=false;
Initiate P1, P2
End (mutex)

Program : Mutual Exclusion Algorithm

P1 first sets P1busy and then tests P2busy to determine what to do next. When it
finds P2busy to be false, process P1 may safely proceed to the Critical section
knowing that no matter how the two processes may be interleaved, process P2 is
certain to find P2busy set and to stay away from the critical section. The single
change ensures mutual exclusion.

But consider a case where P1 wishes to enter the critical section and sets P1busy
to indicate the fact. If process P2 wishes to enter the critical section at the same
time and pre-empts process P1 just before P1 tests P2busy.

Process P2 may set P2busy and start looping while waiting for P1busy to become
false. When control is eventually returned to Process P1, it finds P2busy set and
starts looping while it waits for P2busy to become false. And so both processes are looping forever,
each awaiting the other one to clear the way. In order to remove this kind of behavior, we must add
another requirement to occur in our algorithm. When more than one process wishes to enter the
critical section, the decision to grant entrance to one of them must be made in finite time.

Peterson’s Solution:
Next, we illustrate a classic software-based solution to the critical-section problem known as
Peterson’s solution. Because of the way modern computer architectures perform basic machine-
language instructions, such as load and store , there are no guarantees that Peterson’s solution will
work correctly on such architectures. However, we present the solution because it provides a good
algorithmic description of solving the critical-section problem and illustrates some of the
complexities involved in designing software that addresses the requirements of mutual exclusion,
progress, and bounded waiting.

Peterson’s solution is restricted to two processes that alternate execution between their critical
sections and remainder sections. The processes are numbered P 0 and P 1 . For convenience, when
presenting P i , we use P j to denote the other process; that is, j equals 1 − i . Peterson’s solution
requires the two processes to share two data items:
int turn;
boolean flag[2];

The variable turn indicates whose turn it is to enter its critical section. That is, if turn == i , then
process P i is allowed to execute in its critical section. The flag array is used to indicate if a process
is ready to enter its critical section. For example, if flag[i] is true , this value indicates that P i is
ready to enter its critical section.

To enter the critical section, process P i first sets flag[i] to be true and then sets turn to the value j ,
thereby asserting that if the other process wishes to enter the critical section, it can do so. If both
processes try to enter at the same time,then the eventual value of turn determines which of the two
processes is allowed to enter its critical section first.

PROCESS Pi Code:
while (true) {
flag[i] = TRUE ;
turn = j;
while (flag[j] && turn == j)
waiting to enter Critical section;
critical section
flag[i] = FALSE ;
remainder section
}
The structure of process P i in Peterson’s solution.

We now prove that this solution is correct. We need to show that:


1. Mutual exclusion is preserved.
2. The progress requirement is satisfied.
3. The bounded-waiting requirement is met.

To prove property 1, we note that each P i enters its critical section only if either flag[j] == false or
turn == i . Also note that, if both processes can be executing in their critical sections at the same
time, then flag[0] == flag[1] == true . These two observations imply that P 0 and P 1 could not have
successfully executed their while statements at about the same time, since the value of turn can be
either 0 or 1 but cannot be both. Hence, one of the processes —say, P j —must have successfully
executed the w hile statement, whereas P i had to execute at least one additional statement (“ turn
== j ”). However, at that time, flag[j] == true and turn == j , and this condition persists as long as P j
is in its critical section; as a result, mutual exclusion is preserved.

To prove properties 2 and 3, we note that a process P i can be prevented from entering the critical
section only if it is stuck in the w hile loop with the condition flag[j] == true and turn == j ; this
loop is the only one possible. If P j is not ready to enter the critical section, then flag[j] == false ,
and P i can enter its critical section. If P j has set flag[j] to true and is also executing in its while
statement, then either turn == i or turn == j . If turn == i , then P i will enter the critical section. If
turn == j , then P j will enter the critical section. However, once P j exits its critical section, it will
reset flag[j] to false , allowing P i to enter its critical section. If P j resets flag[j] to true , it must also
set turn to i . Thus, since P i does not change the value of the variable turn while executing the while
statement, P i will enter the critical section (progress) after at most one entry by P j (bounded
waiting).

Synchronization Hardware:

The critical-section problem can be solved in a uni-processor environment if we can forbid


interrupts to occur while a shared variable is being modified. In this manner, we could be sure that
the current sequence of instructions would be allowed to execute in order without preemption. No
other instructions would be run, so no unexpected modifications could be made to the shared
variable. This solution is not feasible in a multiprocessor environment. Disabling interrupts on a
multiprocessor can be time-consuming, as the message is passed to all the processors. This message
passing delays entry into each critical section, and system efficiency decreases. Many machines
provide special hardware instructions that allow us either to test and modify the content of a word
or to swap the contents of two words, atomically - as one uninterruptible unit. These special
instructions can be used to solve the critical-section problem. The TestAndSet instruction can be
defined as follows:

Boolean TestAndSet (Boolean &target)


{
Boolean rv = target;
Target = true;
Return rv;
}

Definition of the TestAndSet instruction.


The important characteristic is that this instruction is executed atomically. Thus, if
two TestAndSet instructions are executed simultaneously, each on a different CPU,
they will be executed sequentially in some arbitrary order. If the machine supports
the TestAndSet instruction, then we can implement mutual exclusion by declaring,
a Boolean variable lock, initialized to false. The structure of the process is as
follows:
do {
while (TestAndSet(lock));
critical section
lock = false;
remainder section
}while(1)
Fig : Mutual-exclusion implementation with TestAndSet.

The Swap instruction can be defined as follows:


void Swap(Boolean &a, Boolean &b)
{
Boolean temp = a;
a = b;
b = temp;
}
Fig : Definition of the Swap instruction.

It operates on the contents of two words and it is executed atomically. If the


machine supports the Swap instruction, then the mutual exclusion can be provided
by declaring a variable lock and is initialized to false. In addition, each process
also has a local Boolean variable key. The structure of the process is as follows:
do {
key = true;
while (key == true)
Swap(lock, key);
Critical section
lock = false;
remainder section
}while(1);

These algorithms do not satisfy the bounded-waiting requirement. The following is


an algorithm that uses the TestAndSet instruction satisfies all the critical-section
requirements. The common data structures are
Boolean waiting[n];
Boolean lock;
These data structures are initialized to false.

do {
waiting[i] = true;
key = ture;
while (waiting[i] && key)
key = TestAndSet(lock);
waiting[i] = flase;

critical section

j = (i+1) % n;
while ((j != i) && !waiting[j])
j = (j+1) % n;
if (j == i)
lock = false;
else
waiting[j] = false;

remainder section
} while(1);

Fig : Bounded-waiting mutual exclusion with TestAndSet.

To prove that the mutual exclusion requirement is met, note that process Pi can
enter its critical section only if either waiting[i] == flase or key == flase. The
value of key can become false only if the TestAndSet is executed. The first process
to execute the TestAndSet will find key == flase; all others must wait. The
variable waiting[i] can become false only if another process leaves its critical
section; only one waiting[i] is set to false, maintaining the mutual exclusion
requirement.

To prove the progress requirement is met, note that a process exiting the critical
section either sets lock to false, or sets waiting[i] to false. Both allow a process
that is waiting to enter its critical section to proceed.

To prove the bounded-waiting requirement is met, when a process leaves its


critical section, it scans the array waiting in the cyclic ordering (i+1, i+2, … n-1, 0,
1, …, i-1). It designates the first process in this ordering that is in the entry
section (waiting[j] == true) as the next one to enter the critical section. Any
process waiting to enter its critical section will thus do so within n-1 turns.

Semaphores:

To overcome the mutual exclusion problem, a synchronization tool called


semaphore was proposed by Dijkstra which gained wide acceptance and
implemented in several commercial operating system through system calls or as
built-in functions.

A semaphore is a variable which accepts non-negative integer values and except


for initialization may be accessed and manipulated through two primitive
operations - wait and signal (originally defined as P and V respectively). These
names come from the Dutch words Problem (to test) and Verogen (to increment).
The two primitives take only argument as the semaphore variable, and may be
defined as follows.

a. Wait(s):
while S <= 0 do (keep testing);
S: = S-1;
wait operation decrements the value of semaphore variable as soon as it
would become non-negative.
b. Signal(s) S:= S+1;
Signal operation increments the value of semaphore variable.

Modifications to the integer value of the semaphore in the wait and signal
operations are executed indivisibly. That is, when one process modifies the
semaphore no other process can simultaneously modify the same semaphore
value. In addition in the case of wait(s), the testing of the integer value of S (S
<= 0) and its possible modification (S :=S-1) must also be executed without any
interruption.

Operating systems often distinguish between counting and binary semaphores.


The value of a counting semaphore can range over an unrestricted domain. The
value of a binary semaphore can range only between 0 and 1. On some
systems, binary semaphores are known as mutex locks, as they are locks that
provide mutual exclusion.

We can use binary semaphores to deal with the critical-section problem for
multiple processes. Counting semaphores can be used to control access to a given
resource consisting of a finite number of instances. The semaphore is initialized to
the number of resources available. Each process that wishes to use a resource
perform a wait() operation on the semaphore (thereby decrementing the count).
When a process releases a resource, it perform a signal() operation (incrementing
the count). When the count for the semaphore goes to 0, all resources are being
used. After that, processes that wish to use a resource will block until the count
becomes greater than 0.

Program 2 demonstrates the functioning of semaphores. In this program, there


are 3 processes to trying to share a common resource which is being protected by
a binary semaphore (bsem). (A binary semaphore is a variable which contains only
values of 0 and 1) by enforcing its use in mutually exclusive fashion. Each process
ensures the integrity of its critical section by opening it with a WAIT operation and
closing with a SIGNAL operation on the related semaphore, bsem in our example.
This way any number of concurrent processor might share the resource provided
each of these process use wait and signal operation.

The parent process in the program first initializes binary semaphore variable bsem
to 1 indicating that the source is available. As shown in the table (figure 8) at time
T1 no process is active to share the resource. But at time T2 all the three
processes become active and want to enter their critical sections to share the
resource by running the wait operation. At T2, the bsem is decremented to 0
which indicates that some processes has been given permission to enter the
critical section. At time T3, we find that it is P1 which has been given some
permission. One important thing is to be noted that only one process is allowed by
semaphore at a time to the critical section.

Once P1 is given the permission, it prevents other processes P2 & P3 to read the
value of bsem as 1 till the wait operation of P1 decrements bsem to 0. This is why
wait operation is executed without interruption.
After grabbing the control from semaphore P1 starts sharing the resource which is
depicted at time T3. At T4, P1 executes signal operation to release the resource
and comes out of its critical section. As shown in the table that the value of bsem
becomes 1 since the resource is now free.
The two remaining processes P2 and P3 have an equal chance to compete the
resource. In our example, process P3 become the next to enter the critical section
and to use the shared resource. At time T7, process P3 releases the resource and
semaphore variable bsem again becomes 1. At this time, the two other processes
P1 and P2 will attempt to compete for the resource and they have equal chance to
get access.

In our example, it is P2 which gets the chance but it might happens one of the
three processes could have never got the chance.
module Sem-mutex var bsem : semaphore; {binary
semaphore)
process P1;
Begin
while true do
wait (bsem);
Critical_section
Signal (bsem);
The rest_of P1_Processing
end; (P1)

process P2;
Begin
while true do
wait (bsem);
Critical-section;
signal (bsem);
The rest of P2-Processing
end; (P2)

process P3;
Begin
while true do
wait (bsem);
Critical-section;
signal (bsem);
The rest of P3-Processing
end; (P3)

(Parent process)
begin (sem-mutex)
bsem:= 1; (free)
initiate P1, P2, P3;
end; (Mutux)
Program 2. Mutual Exclusion with Semaphore
Figure 8: Run time behaviour of Process

We also present a table (figure 8) showing the run time behaviour of three
processes and functioning of semaphore. Each column of the table show the
activity of a particular process and the value of a semaphore after certain action
has been taken on this process.
Classical Problems of Synchronization

• Bounded-Buffer Problem

To avoid the occurrence of race condition, we present a solution to the bounded-


buffer problem using semaphores. The biggest advantage of this solution using
semaphores is that it not only avoids the occurrence of race condition but also
allows to have size items in the buffer at the same time, thus, eliminating the
shortcomings of the solutions using shared memory. The following three
semaphores are used in this solution.

We assume that the pool consists of n buffers, each capable of holding one item.
The mutex semaphore provides mutual exclusion for accesses to the buffer pool
and is initialized to the value 1. The empty and full semaphores count the number
of empty and full buffers. The semaphore empty is initialized to the value n; the
semaphore full if initialized to the value 0.

The structure of the producer process


while (true) {
// produce an item
wait (empty);
wait (mutex);
// add the item to the buffer
signal (mutex);
signal (full);
}

The structure of the consumer process

while (true) {

wait (full);

wait (mutex);

// remove an item from buffer

signal (mutex);
signal (empty);

// consume the removed item

We can interpret these codes as the producer producing full buffers for the
consumer or as the consumer producing empty buffers for the producer.

• Readers and Writers Problem

Concurrently executing processes that are sharing a data object, such as a file or a
variable, fall into two groups: readers and writers. The processes in the readers
group want only to read the contents of the shared object, whereas, the
processes in writers group want to update (read and write) the value of shared
object. There is no problem if multiple readers access the shared object
simultaneously. However, if a writer and some other process (either a reader or
writer) access the shared object simultaneously, data may become inconsistent.

To ensure that such a problem does not arise, we must guarantee that when a
writer is accessing the shared object, no reader or writer accesses that shared
object. This synchronization problem is termed as readers-writers problem. The
readers-writers problem has several variations. The simplest one referred to as the
first reader-writer problem, requires that no reader will be kept waiting unless a
writer has already obtained permission to use the shared object. In other words,
no reader should wait for others readers to finish simply because a writer is
waiting. The second readers-writers problem requires that, once a writer is ready,
that writer performs its write as soon as possible. In other words, if a writer is
waiting to access the object, no new readers may start reading.

A solution to either problem may result in starvation. In the first case writers may
starve, in the second case, readers may starve.
Following is a solution to the first readers-writers problem. The reader process
share the following data structures:
semaphore mutex, wrt;
int readcount;

The semaphore mutex and wrt are initialized to 1 and readcount is initialized to 0.
The semaphore wrt is common to both reader and writer processes. The mutex
semaphore is used to ensure mutual exclusion when the variable readcount is
updated. The readcount variable keeps track of how many processes are currently
reading the object. The semaphore wrt functions as a mutual-exclusion semaphore
for the writers. It is also used by the first or last reader that enters or exists the
critical section. It is not used by readers who enter or exit while other readers are
in their critical section.

If a writer is in the critical section and n readers are waiting, then one reader is
queued on wrt, and n-1 readers are queued on mutex. Also, observe that, when a
writer executes signal(wrt), we may resume the execution of either the waiting
readers or a single waiting writer.

The structure of a writer process

while (true) {
wait (wrt) ;

// writing is performed
signal (wrt) ;
}

The structure of a reader process

while (true) {
wait (mutex) ;
readcount ++ ;
if (readercount == 1) wait (wrt) ;
signal (mutex)

// reading is performed
wait (mutex) ;
readcount - - ;
if (redacount == 0) signal (wrt) ;
signal (mutex) ;
}

• Dining-Philosophers Problem

Consider five philosophers sitting around a circular table. There is a bowl of rice in
the centre of the table and five chopsticks – one in between each pair of
philosophers.

Initially, all the philosophers are in the thinking phase and while thinking, they
make sure that they do not interact with each other. As time passes by,
philosophers might feel hungry. When a philosopher feels hungry, he attempts to
pick up the two chopsticks kept in close proximity to him ( that are in between him
and his left and his right philosophers). If the philosophers on his left and right are
not eating, he successfully gets the two chopsticks. With the two chopsticks in his
hand, he starts eating. After he finishes eating, the chopsticks are positioned back
on the table and the philosopher begins to think again. On the contrary, if the
philosopher on his left or right is already eating, then fails to grab the two
chopsticks at the same time, and thus, has to wait.

A solution to this problem is to represent each chopstick as a semaphore, and


philosophers must grab or release chopsticks by executing wait operation or signal
operation respectively on the appropriate semaphores. We use an array chopstick
of size 5 where each element is initialized to 1.

The structure of Philosopher i:


While (true) {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );

// eat
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );

// think
}
This solution is simple and ensure that no two neighbors are eating at the same
time. However, the solution is not free from deadlock. Suppose all the
philosophers attempt to grab the chopsticks simultaneously and grab one
chopstick successfully. In this case, all the elements of chopstick will be 0. Thus,
when each philosopher attempts to grab the second chopstick, he will go in waiting
state forever.
Several possible remedies to the deadlock problem are available:
• Allow at most four philosophers to be sitting simultaneously at the table.
• Allow a philosopher to pick up his chopsticks only if both chopsticks are
available.
• Use an asymmetric solution; that is, an odd philosopher picks up first his left
chopstick and then his right chopsticks, whereas an even philosopher picks
up his right chopstick and then her left chopstick.
Dining-philosophers problem can be solved with the use of monitors.
Monitors

A monitor is a programming language construct which is also used to provide


mutually exclusive access to critical sections. The programmer defines monitor
type which consists of declaration of shared data (or variables), procedures or
functions that access these variables, and initialization code. The general syntax of
declaring syntax of declaring a monitor type is as follows:

monitor <monitor-name>
{
// shared data ( or variable) declarations
data type <variable-name>;

// function (or procedure) declarations
return_type <function_name> (parameters)
{
// body of function
}
.
.
monitor-name()
{
// initialization
}
}

The variables defined inside a monitor can only be accessed by the functions
defined within the monitor, and it is not feasible for any process to access these
variables. Thus, if any process has to access these variables, it is only possible
through the execution of the functions defined inside the monitor. Further, the
monitor construct checks that only one process may be executing within the
monitor at a given moment. But if a process is executing within the monitor, then
other requesting processes are blocked and placed on an entry queue.
Schematic view of a monitor

However, the monitor construct, as defined so far, is not sufficiently powerful for
modeling some synchronization schemes. For this purpose, we need to define
additional synchronization mechanisms. These mechanisms are provided by the
condition construct. We can define a mechanism by defining variables of
condition type on which only two operations can be invoked: wait and signal.

Suppose, programmer defines a variable C of condition type, then execution of


the operation C.wait() by a process Pi, suspends the execution of Pi, and places
it on a queue associated with the condition variable C. On the other hand, the
execution of the operation C.signal() by a process Pi, resumes the execution of
exactly one suspended process Pj, if any. It means that the execution of the
signal operation by Pi allows other suspended process Pj to execute within the
monitor. However, only one process is allowed to execute within the monitor at
one time. Thus, monitor construct prevents Pj from resuming until Pi is executing
in the monitor. There are following possibilities to handle this situation.
• The process Pi must be suspended to allow Pj to resume and wait until Pj
leaves the monitor.
• The process Pj must remain suspended until Pi leaves the monitor.
• The process Pi must execute the signal operation as its last statement in
the monitor so that Pj can resume immediately.

The solution to the dining-philosophers problem is as follows:


The distribution of the chopsticks is controlled by the monitor dp. Each
philosopher, before starting to eat, must invoke the operation pickup(). This may
result in the suspension of the philosopher process. After the successful
completion of the operation, the philosopher may eat. Following this, the
philosopher invokes the putdown() operation. Thus, philosopher i must invoke
the operations pickup() and putdown() in the following sequence:

dp.pickup(i);

eat

dp.putdown(i);

monitor DP
{
enum { THINKING; HUNGRY, EATING) state [5] ;
condition self [5];
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING)
self [i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}

void test (int i) {


if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) )
{
state[i] = EATING ;
self[i].signal () ;
}
}
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
After eating is finished, each philosopher invokes putdown() operation before
start thinking. This operation changes the state of philosopher process to thinking
and then invoke test((i + 4) % 5) and test((i + 1) % 5) operation for
philosophers on his left and right side (one by one). This verifies whether the
philosopher feels hungry, and if so then allows him to eat in case philosophers on
his left and right side are not eating.
OPERATING SYSTEM - MULTI-THREADING
http://www.tuto rialspo int.co m/o pe rating _syste m/o s_multi_thre ading .htm Co pyrig ht © tuto rials po int.co m

What is Thread?
A thread is a flow of execution throug h the process code, with its own prog ram counter, system reg isters and
stack. A thread is also called a lig ht weig ht process. T hreads provide a way to improve application performance
throug h parallelism. T hreads represent a software approach to improving performance of operating system by
reducing the overhead thread is equivalent to a classical process.

Each thread belong s to exactly one process and no thread can exist outside a process. Each thread represents
a separate flow of control.T hreads have been successfully used in implementing network servers and web
server. T hey also provide a suitable foundation for parallel execution of applications on shared memory
multiprocessors. Folowing fig ure shows the working of the sing le and multithreaded processes.

Difference between Process and Thread

S.N. Proc ess T hread

1 Process is heavy weig ht or resource intensive. T hread is lig ht weig ht taking lesser resources
than a process.

1 Process switching needs interaction with T hread switching does not need to interact with
operating system. operating system.

1 In multiple processing environments each All threads can share same set of open files, child
process executes the same code but has its processes.
own memory and file resources.

1 If one process is blocked then no other While one thread is blocked and waiting , second
process can execute until the first process is thread in the same task can run.
unblocked.

1 Multiple processes without using threads use Multiple threaded processes use fewer
more resources. resources.
1 In multiple processes each process operates One thread can read, write or chang e another
independently of the others. thread's data.

Advantag es of Thread
T hread minimize context switching time.

Use of threads provides concurrency within a process.

Efficient communication.

Economy- It is more economical to create and context switch threads.

Utilization of multiprocessor architectures to a g reater scale and efficiency.

Types of Thread
T hreads are implemented in following two ways

User Level T hreads -- User manag ed threads

Kernel Level T hreads -- Operating System manag ed threads acting on kernel, an operating system
core.

User Level Threads


In this case, application manag es thread manag ement kernel is not aware of the existence of threads. T he thread
library contains code for creating and destroying threads, for passing messag e and data between threads, for
scheduling thread execution and for saving and restoring thread contexts. T he application beg ins with a sing le
thread and beg ins running in that thread.

Advantag es
T hread switching does not require Kernel mode privileg es.

User level thread can run on any operating system.

Scheduling can be application specific in the user level thread.

User level threads are fast to create and manag e.


Disadvantag es
In a typical operating system, most system calls are blocking .

Multithreaded application cannot take advantag e of multiprocessing .

Kernel Level Threads


In this case, thread manag ement done by the Kernel. T here is no thread manag ement code in the application
area. Kernel threads are supported directly by the operating system. Any application can be prog rammed to be
multithreaded. All of the threads within an application are supported within a sing le process.

T he Kernel maintains context information for the process as a whole and for individuals threads within the
process. Scheduling by the Kernel is done on a thread basis. T he Kernel performs thread creation, scheduling
and manag ement in Kernel space. Kernel threads are g enerally slower to create and manag e than the user
threads.

Advantag es
Kernel can simultaneously schedule multiple threads from the same process on multiple processes.

If one thread in a process is blocked, the Kernel can schedule another thread of the same process.

Kernel routines themselves can multithreaded.

Disadvantag es
Kernel threads are g enerally slower to create and manag e than the user threads.

T ransfer of control from one thread to another within same process requires a mode switch to the Kernel.

Multithreading Models
Some operating system provide a combined user level thread and Kernel level thread facility. Solaris is a g ood
example of this combined approach. In a combined system, multiple threads within the same application can run in
parallel on multiple processors and a blocking system call need not block the entire process. Multithreading
models are three types

Many to many relationship.

Many to one relationship.

One to one relationship.

Many to Many Model


In this model, many user level threads multiplexes to the Kernel thread of smaller or equal numbers. T he number
of Kernel threads may be specific to either a particular application or a particular machine.

Following diag ram shows the many to many model. In this model, developers can create as many user threads as
necessary and the corresponding Kernel threads can run in parallels on a multiprocessor.
Many to One Model
Many to one model maps many user level threads to one Kernel level thread. T hread manag ement is done in
user space. When thread makes a blocking system call, the entire process will be blocks. Only one thread can
access the Kernel at a time,so multiple threads are unable to run in parallel on multiprocessors.

If the user level thread libraries are implemented in the operating system in such a way that system does not
support them then Kernel threads use the many to one relationship modes.

One to One Model


T here is one to one relationship of user level thread to the kernel level thread.T his model provides more
concurrency than the many to one model. It also another thread to run when a thread makes a blocking system
call. It support multiple thread to execute in parallel on microprocessors.

Disadvantag e of this model is that creating user thread requires the corresponding Kernel thread. OS/2,
windows NT and windows 2000 use one to one relationship model.
Difference between User Level & Kernel Level Thread

S.N. User Level T hreads Kernel Level T hread

1 User level threads are faster to create and Kernel level threads are slower to create and
manag e. manag e.

2 Implementation is by a thread library at the user Operating system supports creation of Kernel
level. threads.

3 User level thread is g eneric and can run on any Kernel level thread is specific to the operating
operating system. system.

4 Multi-threaded application cannot take Kernel routines themselves can be multithreaded.


advantag e of multiprocessing .
Previous examination Questions:

1Q. a) Explain multithreading. Distinguish between single threaded process multithreaded process
b) Explain Peterson’s solution to Critical Section Problem. [ 6 + 6 M ,April 2014 ]

2Q. a) Define context switching. Explain queuing diagram representation of process scheduling. 6M
b) Write short notes on monitors and semaphores. 6M [April 2014]

3Q. a)Explain the solution to Dining philosopher problem. 8M


b)Define mutual exclusive with busy wait. 4M [April 2013]

4Q. a) Define Monitor. 4M [April 2012]


b) Explain the solution for producer consumer problem using Semaphore and Monitor. 8M

5Q. Give the solution of Reader – Writers Problem. 8M [April 2012]

6Q. a) Explain the critical section problem and describe the Peterson’s solution for the same.
b) Explain the Readers-Writers synchronization problem and describe the solution using
semaphores [ 6 + 6 Marks April 2011]

7Q. a) Explain the structure and syntax of a monitor. [6 + 6 M April 2011]


b) Give a solution to the classic five dining philosopher’s problem using monitor.

8Q. a) Describe
i) Shortest Job First scheduling
ii) Priority scheduling 6
b) Explain the scheduling criteria. 6 [ Apirl 2011]

Review Questions:

1Q. Describe the differences among short-term, medium-term, and long-term scheduling.
2Q. Describe the actions taken by a kernel to context-switch between processes.

***NOTE: Also concentrate other topics which are not covered in this questions.

You might also like