0% found this document useful (0 votes)
23 views

Unit-2 Os

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

Unit-2 Os

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

UNIT-II

PROCESSES
1.3.1 Process concepts
Process : A process is a program in execution. A process is more than the program code, which is
sometimes known as the text section. It also includes the current activity, as represented by the value of
the program counter and the contents of the processor's registers. A process generally also includes the
process stack, which contains temporary data (such as function parameters, return addresses, and local
variables), and a data section, which contains global variables. A process may also include a heap, which
is memory that is dynamically allocated during process run time.

Structure of a process
We emphasize that a program by itself is not a process; a program is a passive entity, such as a file
containing a list of instructions stored on disk (often called an executable file), whereas a process is an
active entity, with a program counter specifying the next instruction to execute and a set of associated
resources. A program becomes a process when an executable file is loaded into memory.
Two common techniques for loading executable files are double-clicking an icon representing the
executable file and entering the name of the executable file on the command line (as in prog. exe or
a.out.)

Process

We emphasize that a program by itself is not a process; a program is a passive entity, such as a file
containing a list of instructions stored on disk (often called an executable file), whereas a process
is an active entity, with a program counter specifying the next instruction to execute and a set of
associated resources. A program becomes a process when an executable file is loaded into memory.
Two common techniques for loading executable files are double-clicking an icon representing the
executable file and entering the name of the executable file on the command line (as in prog. exe or
a.out.)
Process State
As a process executes, it changes 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:
• New. The process is being created.
• Running. Instructions are being executed.
• Waiting. The process is waiting for some event to occur (such as an I/O
completion or reception of a signal).
• Ready. The process is waiting to be assigned to a processor.
• Terminated. The process has finished execution. These names are arbitrary, and they vary across
operating systems. The states that they represent are fotind on all systems, however. Certain operating
systems also more finely delineate process states. It is important to realize that only one process can be
running on any processor at any instant.

Process Control Block


Each process is represented in the operating system by a process control block (PCB)—also
called a task control block.

Process state. The state may be new, ready, running, and waiting, halted, and so on.

Program counter-The counter indicates the address of the next instruction to be executed for this
process.
• CPU registers- The registers vary in number and type, depending on the computer architecture.
They include accumulators, index registers, stack pointers, and general-purpose registers, plus any
condition code information.

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 such 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 members, job or process numbers, and so on.

I/O status information-This information includes the list of I/O devices allocated to the process,
a list of open files, and so on.

1.3.2 Process Scheduling


The process scheduler selects an available process (possibly from a set of several available
processes) for program execution on the CPU. As processes enter the system, they are put into a job
queue, which 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 PCBs in the list. Each PCB includes a pointer field that points to the next PCB in the ready queue.
The process scheduler selects an available process (possibly from a set of several available
processes) for program execution on the CPU. As processes enter the system, they are put into a job
queue, which 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 PCBs in the list. Each PCB includes a pointer field that points to the next PCB in the ready queue.
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 till 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 sub process and wait for the sub process’s termination.
• The process could be removed forcibly from the CPU, as a result of an interrupt, and be put back in the
ready queue.

Schedulers
A process migrates among the various scheduling queues throughout its lifetime. The operating system
must select, for scheduling purposes, processes from these queues in some fashion.
The selection process is carried out by the appropriate scheduler. The long-term scheduler,
or job scheduler, selects processes from this pool and loads them into memory for execution. The
short-term scheduler, or CPU scheduler, selects from among the processes that are ready
to execute and allocates the CPU to one of them.

1.3.3 Operations on Processes


Process Creation
A process may create several new processes, via a create-process system call, during the course of
execution. The creating process is called a parent process, and the new processes are called the
children of that process. Each of these new processes may in turn create other processes, forming a
tree of processes.

Most operating systems identify processes according to a unique process identifier (or pid),
which is typically an integer number. These processes are responsible for managing memory and file
systems. The sched process also creates the init process, which serves as the root parent process for all
user processes.

When a process creates a new process, two possibilities exist in terms of execution:
1. The parent continues to execute concurrently with its children.
2. The parent waits until some or all of its children have terminated.
There are also two possibilities in terms of the address space of the new process:
1. The child process is a duplicate of the parent process (it has the same program and data as the parent).
2. The child process has a new program loaded into it.
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid-t pid;
/* fork a child process */
pid = fork();
if (pid < 0) {/* error occurred */
fprintf(stderr, "Fork Failed");
exit (-1) ;
}
else if (pid == 0} {/* child process */
execlpf"/bin/Is","Is",NULL);
}
else {/* parent process */
/* parent will wait for the child to complete */
wait(NULL);
printf("Child Complete");
exit (0) ;
}
}

In UNIX, as we've seen, each process is identified by its process identifier, which is a unique integer. A
new process is created by the fork() system call. The new process consists of a copy of the address space
of the original process.
This mechanism allows the parent process to communicate easily with its child process. Both processes
(the parent and the child) continue execution at the instruction after the fork(), with one difference: The
return code for the fork() is zero for the new (child) process, whereas the (nonzero) process identifier of
the child is returned to the parent. the exec() system call is used after a fork() system call by one of the
two processes to replace the process's memory space with a new program.
The exec () system call loads a binary file into memory (destroying the memory image of the program
containing the execO system call) and starts its execution.

Process Termination
A process terminates when it finishes executing its final statement and asks the operating system to delete
it by using the exit () system call. At that point, the process may return a status value (typically an integer)
to its parent process (via the wait() system call). All the resources of the process—including physical and
virtual memory, open files, and I/O buffers—are deal located by the operating system.
Termination can occur in other circumstances as well. A process can cause the termination of
another process via an appropriate system call (for example, TerminateProcessO in Win32). Usually, such
a system call can be invoked only by the parent of the process that is to be terminated.
A parent may terminate the execution of one of its children for a variety of reasons, such as these:
• The child has exceeded its usage of some of the resources that it has been allocated.
• The task assigned to the child is no longer required.
• The parent is exiting, and the operating system does not allow a child to
continue if its parent terminates.
Consider that, in UNIX, we can terminate a process by using the exit() system call; its parent
process may wait for the termination of a child process by using the wait() system call. The wait () system
call returns the process identifier of a terminated child so that the parent can tell which of its possibly
many children has terminated.
If the parent terminates, however, all its children have assigned as their new parent the init
process.

1.3.4 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.
There are several reasons for providing an environment that allows process cooperation:

• Information sharing. Since several users may be interested in the same piece of information (for
instance, a shared file), 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. Notice that such a speedup can be achieved only if the
computer has multiple processing elements (such as CPUs or I/O channels).
• 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
many 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. There are two fundamental models of interprocess
communication:

(1) shared memory and (2) message passing. 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. In the message passing model, communication takes place
by means of messages exchanged between the cooperating processes.

Message passing is useful for exchanging smaller amounts of data, because no conflicts need be
avoided. Message passing is also easier to implement than is shared memory for intercomputer
communication. Shared memory allows maximum speed and convenience of communication, as it can be
done at memory speeds when within a computer.

Shared memory is faster than message passing, as message-passing systems are typically
implemented using system calls and thus require the more time consuming task of kernel intervention.

Shared-Memory Systems Interprocess communication using shared memory requires communicating


processes to establish a region of shared memory.
Typically, a shared-memory region resides in the address space of the process creating the shared-
memory segment. Other processes that wish to communicate using this shared-memory segment must
attach it to their address space.
The operating system tries to prevent one process from accessing another process's memory. Shared
memory requires that two or more processes agree to remove this restriction. They can then exchange
information by reading and writing data in the shared areas.

The form of the data and the location are determined by these processes and are not under the operating
system's control. The processes are also responsible for ensuring that they are not writing to the same
location simultaneously.
Message-Passing Systems The scheme requires that these processes share a region of memory
and that the code for accessing and manipulating the shared memory be written explicitly by the
application programmer. Another way to achieve the same effect is for the operating system to provide
the means for cooperating processes to communicate with each other via a message-passing facility.

Message passing provides a mechanism to allow processes to communicate and to synchronize their
actions without sharing the same address space and is particularly useful in a distributed environment,
where the communicating processes may reside on different computers connected by a network.
A message-passing facility provides at least two operations: send(message) and receive(message).
Messages sent by a process can be of either fixed or variable size. If only fixed-sized messages can be
sent, the system-level implementation is straightforward. This restriction, however, makes the task of
programming more difficult. Conversely, variable-sized messages require a more complex system-level
implementation, but the programming task becomes simpler. This is a common kind of tradeoff seen
throughout operating system design.

Naming
Processes that want to communicate must have a way to refer to each other. They can use either direct or
indirect communication.
Under direct communication, each process that wants to communicate must explicitly name the recipient
or sender of the communication. In this scheme, the send.0 and receive() primitives are defined as:
• send(P, message)—Send a message to process P.
• receive (Q, message)—Receive a message from process Q.
A communication link in this scheme has the following properties:
• A link is established automatically between every pair of processes that want to communicate. The
processes need to know only each other's identity to communicate.
• A link is associated with exactly two processes.
• Between each pair of processes, there exists exactly one link.
The disadvantage in both of these schemes (symmetric and asymmetric) is the limited modularity of the
resulting process definitions. Changing the identifier of a process may necessitate examining all other
process definitions.

Synchronization
Communication between processes takes place through calls to send() and receive () primitives. There are
different design options for implementing each primitive. Message passing may be either blocking or
nonblocking— also known as synchronous and asynchronous.

• Blocking send- The sending process is blocked until the message is received by the receiving
process or by the mailbox.

• Nonblocking send- The sending process sends the message and resumes operation.
• Blocking receive- The receiver blocks until a message is available.

• Nonblocking receive- The receiver retrieves either a valid message or a null.


Buffering

Whether communication is direct or indirect, messages exchanged by communicating processes reside in


a temporary queue. Basically, such queues can be implemented in three ways:

• Zero capacity- The queue has a maximum length of zero; thus, the link cannot have any messages
waiting in it. In this case, the sender must block until the recipient receives the
message.

• Bounded capacity- The queue has finite length n; thus, at most n messages can reside in it. If
the queue is not full when a new message is sent, the message is placed in the queue (either the message
is copied or a pointer to the message is kept), and the sender can continue execution without waiting. The
links capacity is finite, however. If the link is full, the sender must block until space is available in the
queue.

• Unbounded capacity- The queues length is potentially infinite; thus, any number of messages
can wait in it. The sender never blocks.

1.3.5 Examples of IPC Systems


An Example: POSIX Shared Memory
Several IPC mechanisms are available for POSIX systems, including shared memory and message
passing. A process must first create a shared memory segment using the shmget () system call (shmget ()
is derived from SHared Memory GET).

The following example illustrates the use of shmget ():


segment_id = shmget(IPCJPRIVATE, size, SJRUSR | SJVVUSR) ;
This first parameter specifies the key (or identifier) of the shared-memory segment. If this is set to
IPCPRIVATE, a new shared-memory segment is created. The second parameter specifies the size (in
bytes) of the shared memory segment. Finally, the third parameter identifies the mode, which indicates
how the shared-memory segment is to be used—that is, for reading, writing, or both. By setting the mode
to SJRUSR | SJVVUSR, we are indicating that the owner may read or write to the shared memory
segment.

Processes that wish to access a shared-memory segment must attach it to their address space
using the shmat () (SHared Memory ATtach) system call.
The call to shmat () expects three parameters as well. The first is the integer identifier of the
shared-memory segment being attached, and the second is a pointer location in memory indicating where
the shared memory will be attached.
If we pass a value of NULL, the operating system selects the location on the user's behalf. The third
parameter identifies a flag that allows the shared memory region to be attached in read-only or read-write
mode; by passing a parameter of 0, we allow both reads and writes to the shared region.

The third parameter identifies a mode flag. If set, the mode flag allows the shared-memory region to be
attached in read-only mode; if set to 0, the flag allows both reads and writes to the shared region.

We attach a region of shared memory using shmat () as follows:


shared_memory = (char *) shmat(id, NULL, 0);
If successful, shmat () returns a pointer to the beginning location in memory where the shared-memory
region has been attached.

An Example: Windows XP
The Windows XP operating system is an example of modern design that employs modularity to increase
functionality and decrease the time needed to implement new features. Windows XP provides support for
multiple operating environments, or subsystems, with which application programs communicate via a
message-passing mechanism. The application programs can be considered clients of the Windows XP
subsystem server.

The message-passing facility in Windows XP is called the local procedure call (LPC) facility.
The LPC in Windows XP communicates between two processes on the same machine. It is similar to the
standard RPC mechanism that is widely used, but it is optimized for and specific to Windows XP.
Windows XP uses a port object to establish and maintain a connection between two processes. Every
client that calls a subsystem needs a communication channel, which is provided by a port object and is
never inherited.
Windows XP uses two types of ports: connection ports and communication ports. They are really the
same but are given different names according to how they are used. Connection ports are named objects
and are visible to all processes

The communication works as follows:


• The client opens a handle to the subsystem's connection port object.
• The client sends a connection request.
• The server creates two private communication ports and returns the handle to one of them to the client.
• The client and server use the corresponding port handle to send messages or callbacks and to listen for
replies.
Windows XP uses two types of message-passing techniques over a port that the client specifies when it
establishes the channel.

The simplest, which is used for small messages, uses the port's message queue as intermediate storage and
copies the message from one process to the other. Under this method, messages of up to 256 bytes can be
sent. If a client needs to send a larger message, it passes the message through a section object, which sets
up a region of shared memory. The client has to decide when it sets up the channel whether or not it will
need to send a large message. If the client determines that it does want to send large messages, it asks for
a section object to be created. Similarly, if the server decides that replies will be large, it creates a section
object. So that the section object can be used, a small message is sent that contains a pointer and size
information about the section object. This method is more complicated than the first method, but it avoids
data copying. In both cases, a callback mechanism can be used when either the client or the server cannot
respond immediately to a request.

Scheduling Algorithms
There are various algorithms which are used by the Operating System to schedule the processes on the
processor in an efficient way.

FCFS Scheduling
First come first serve (FCFS) scheduling algorithm simply schedules the jobs according to their arrival time. The job
which comes first in the ready queue will get the CPU first. The lesser the arrival time of the job, the sooner will the job
get the CPU. FCFS scheduling may cause the problem of starvation if the burst time of the first process is the longest
among all the jobs.

Advantages of FCFS
o Simple

o Easy

o First come, First serv

Disadvantages of FCFS
1. The scheduling method is non preemptive, the process will run to the completion.

2. Due to the non-preemptive nature of the algorithm, the problem of starvation may occur.

3. Although it is easy to implement, but it is poor in performance since the average waiting time is higher as
compare to other scheduling algorithms.
Example
Let's take an example of The FCFS scheduling algorithm. In the Following schedule, there are 5 processes with process
ID P0, P1, P2, P3 and P4. P0 arrives at time 0, P1 at time 1, P2 at time 2, P3 arrives at time 3 and Process P4 arrives at
time 4 in the ready queue. The processes and their respective Arrival and Burst time are given in the following table.
The Turnaround time and the waiting time are calculated by using the following formula.
1. Turn Around Time = Completion Time - Arrival Time
2. Waiting Time = Turnaround time - Burst Time
The average waiting Time is determined by summing the respective waiting time of all the processes and divided the
sum by the total number of processes.

Process Arrival Burst Completion Turn Waiting Time


ID Time Time Time Around
Time

0 0 2 2 2 0

1 1 6 8 7 1

2 2 4 12 8 4

3 3 9 21 18 9

4 4 12 33 29 17

Avg Waiting Time=31/5

(Gantt chart)

Shortest Job First (SJF) Scheduling


Till now, we were scheduling the processes according to their arrival time (in FCFS scheduling). However, SJF
scheduling algorithm, schedules the processes according to their burst time.
In SJF scheduling, the process with the lowest burst time, among the list of available processes in the ready queue, is
going to be scheduled next.
However, it is very difficult to predict the burst time needed for a process hence this algorithm is very difficult to
implement in the system.

Advantages of SJF
1. Maximum throughput

2. Minimum average waiting and turnaround time

Disadvantages of SJF
1. May suffer with the problem of starvation

2. It is not implementable because the exact Burst time for a process can't be known in advance.
There are different techniques available by which, the CPU burst time of the process can be determined. We will discuss
them later in detail.
Example
In the following example, there are five jobs named as P1, P2, P3, P4 and P5. Their arrival time and burst time are given
in the table below.

PID Arrival Time Burst Time Completion Time Turn Waiting Time
Around
Time

1 1 7 8 7 0

2 3 3 13 10 7

3 6 2 10 4 2

4 7 10 31 24 14

5 9 8 21 12 4

Since, No Process arrives at time 0 hence; there will be an empty slot in the Gantt chart from time 0 to 1 (the time at
which the first process arrives).
According to the algorithm, the OS schedules the process which is having the lowest burst time among the available
processes in the ready queue.
Till now, we have only one process in the ready queue hence the scheduler will schedule this to the processor no matter
what is its burst time.
This will be executed till 8 units of time. Till then we have three more processes arrived in the ready queue hence the
scheduler will choose the process with the lowest burst time.
Among the processes given in the table, P3 will be executed next since it is having the lowest burst time among all the
available processes.
So that's how the procedure will go on in shortest job first (SJF) scheduling algorithm.
Avg Waiting Time = 27/5

Shortest Remaining Time First (SRTF) Scheduling


Algorithm
This Algorithm is the preemptive version of SJF scheduling. In SRTF, the execution of the process can
be stopped after certain amount of time. At the arrival of every process, the short term scheduler
schedules the process with the least remaining burst time among the list of available processes and the
running process.
Once all the processes are available in the ready queue, Nopreemption will be done and the algorithm
will work as SJF scheduling. The context of the process is saved in the Process Control Block when the
process is removed from the execution and the next process is scheduled. This PCB is accessed on
the next execution of this process.

Example
In this Example, there are five jobs P1, P2, P3, P4, P5 and P6. Their arrival time and burst time are given
below in the table

Process Arrival Burst Completion Turn Waiting Response


ID Time Time Time Around Time Time
Time

1 0 8 20 20 12 0

2 1 4 10 9 5 1

3 2 2 4 2 0 2

4 3 1 5 2 1 4

5 4 3 13 9 6 10
6 5 2 7 2 0 5

Avg Waiting Time = 24/6


The Gantt chart is prepared according to the arrival and burst time given in the table.
1. Since, at time 0, the only available process is P1 with CPU burst time 8. This is the only available process
in the list therefore it is scheduled.
2. The next process arrives at time unit 1. Since the algorithm we are using is SRTF which is a preemptive
one, the current execution is stopped and the scheduler checks for the process with the least burst time.
Till now, there are two processes available in the ready queue. The OS has executed P1 for one unit of time
till now; the remaining burst time of P1 is 7 units. The burst time of Process P2 is 4 units. Hence Process
P2 is scheduled on the CPU according to the algorithm.
3. The next process P3 arrives at time unit 2. At this time, the execution of process P3 is stopped and the
process with the least remaining burst time is searched. Since the process P3 has 2 unit of burst time hence
it will be given priority over others.
4. The Next Process P4 arrives at time unit 3. At this arrival, the scheduler will stop the execution of P4 and
check which process is having least burst time among the available processes (P1, P2, P3 and P4). P1 and
P2 are having the remaining burst time 7 units and 3 units respectively.
P3 and P4 are having the remaining burst time 1 unit each. Since, both are equal hence the scheduling will
be done according to their arrival time. P3 arrives earlier than P4 and therefore it will be scheduled again.
5. The Next Process P5 arrives at time unit 4. Till this time, the Process P3 has completed its execution and it
is no more in the list. The scheduler will compare the remaining burst time of all the available processes.
Since the burst time of process P4 is 1 which is least among all hence this will be scheduled.
6. The Next Process P6 arrives at time unit 5, till this time, the Process P4 has completed its execution. We
have 4 available processes till now, that are P1 (7), P2 (3), P5 (3) and P6 (2). The Burst time of P6 is the
least among all hence P6 is scheduled. Since, now, all the processes are available hence the algorithm will
now work same as SJF. P6 will be executed till its completion and then the process with the least
remaining time will be scheduled.
Once all the processes arrive, Nopreemption is done and the algorithm will work as SJF.

Round Robin Scheduling Algorithm


Round Robin scheduling algorithm is one of the most popular scheduling algorithm which can actually be implemented
in most of the operating systems. This is the preemptive version of first come first serve scheduling. The Algorithm
focuses on Time Sharing. In this algorithm, every process gets executed in a cyclic way. A certain time slice is defined
in the system which is called time quantum. Each process present in the ready queue is assigned the CPU for that time
quantum, if the execution of the process is completed during that time then the process will terminate else the process
will go back to the ready queue and waits for the next turn to complete the execution.

Advantages
1. It can be actually implementable in the system because it is not depending on the burst time.

2. It doesn't suffer from the problem of starvation or convoy effect.

3. All the jobs get a fare allocation of CPU.

Disadvantages
1. The higher the time quantum, the higher the response time in the system.

2. The lower the time quantum, the higher the context switching overhead in the system.

3. Deciding a perfect time quantum is really a very difficult task in the system.

RR Scheduling Example
Process ID Arrival Burst Time
Time

1 0 5

2 1 6

3 2 3

In
4 3 1

5 4 5

6 6 4

the following example, there are six processes named as P1, P2, P3, P4, P5 and P6. Their arrival time and burst time are
given below in the table. The time quantum of the system is 4 units.
According to the algorithm, we have to maintain the ready queue and the Gantt chart. The structure of both the data
structures will be changed after every scheduling.
Ready Queue:
Initially, at time 0, process P1 arrives which will be scheduled for the time slice 4 units. Hence in the ready queue, there
will be only one process P1 at starting with CPU burst time 5 units.

P1

GANTT chart
The P1 will be executed for 4 units first.

Ready Queue
Meanwhile the execution of P1, four more processes P2, P3, P4 and P5 arrives in the ready queue. P1 has not completed
yet, it needs another 1 unit of time hence it will also be added back to the ready queue.
P2 P3 P4 P5 P1

6 3 1 5 1

GANTT chart
After P1, P2 will be executed for 4 units of time which is shown in the Gantt chart.

Ready Queue
P3 P4 P5 P1 P6 P2

3 1 5 1 4 2

During the execution of P2, one more process P6 is arrived in the ready queue. Since P2 has not completed yet hence, P2
will also be added back to the ready queue with the remaining burst time 2 units.
GANTT chart
After P1 and P2, P3 will get executed for 3 units of time since its CPU burst time is only 3 seconds.

Ready Queue
Since P3 has been completed, hence it will be terminated and not be added to the ready queue. The next process will be
executed is P4.

P4 P5 P1 P6 P2

1 5 1 4 2
GANTT chart
After, P1, P2 and P3, P4 will get executed. Its burst time is only 1 unit which is lesser then the time quantum hence it
will be completed.

Ready Queue
The next process in the ready queue is P5 with 5 units of burst time. Since P4 is completed hence it will not be added
back to the queue.

P5 P1 P6 P2

5 1 4 2

GANTT chart
P5 will be executed for the whole time slice because it requires 5 units of burst time which is higher than the time slice.

Ready Queue
P1 P6 P2 P5

1 4 2 1

P5 has not been completed yet; it will be added back to the queue with the remaining burst time of 1 unit.
GANTT Chart
The process P1 will be given the next turn to complete its execution. Since it only requires 1 unit of burst time hence it
will be completed.
Ready Queue
P1 is completed and will not be added back to the ready queue. The next process P6 requires only 4 units of burst time
and it will be executed next.

P6 P2 P5

4 2 1

GANTT chart
P6 will be executed for 4 units of time till completion.

Ready Queue
P2 P5

2 1

Since P6 is completed, hence it will not be added again to the queue. There are only two processes present in the ready
queue. The Next process P2 requires only 2 units of time.
GANTT Chart
P2 will get executed again, since it only requires only 2 units of time hence this will be completed.
Ready Queue
P5

Now, the only available process in the queue is P5 which requires 1 unit of burst time. Since the time slice is of 4 units
hence it will be completed in the next burst.
GANTT chart
P5 will get executed till completion.

The completion time, Turnaround time and waiting time will be calculated as shown in the table below.
As, we know,

1. Turn Around Time = Completion Time - Arrival Time


2. Waiting Time = Turn Around Time - Burst Time

Process Arrival Burst Completion Turn Around Waiting Time


ID Time Time Time Time

1 0 5 17 17 12

2 1 6 23 22 16

3 2 3 11 9 6
4 3 1 12 9 8

5 4 5 24 20 15

6 6 4 21 15 11

Avg Waiting Time = (12+16+6+8+15+11)/6 = 76/6 units

Non Preemptive Priority Scheduling


In the Non Preemptive Priority scheduling, The Processes are scheduled according to the priority number assigned to
them. Once the process gets scheduled, it will run till the completion. Generally, the lower the priority number, the
higher is the priority of the process. The people might get confused with the priority numbers, hence in the GATE, there
clearly mention which one is the highest priority and which one is the lowest one.
Example
In the Example, there are 7 processes P1, P2, P3, P4, P5, P6 and P7. Their priorities, Arrival Time and burst time are
given in the table.

Process ID Priority Arrival Time Burst Time

1 2 0 3

2 6 2 5

3 3 1 4

4 5 4 2

5 7 6 9

6 4 5 4

7 10 7 10

We can prepare the Gantt chart according to the Non Preemptive priority scheduling.
The Process P1 arrives at time 0 with the burst time of 3 units and the priority number 2. Since No other process has
arrived till now hence the OS will schedule it immediately.
Meanwhile the execution of P1, two more Processes P2 and P3 are arrived. Since the priority of P3 is 3 hence the CPU
will execute P3 over P2.
Meanwhile the execution of P3, All the processes get available in the ready queue. The Process with the lowest priority
number will be given the priority. Since P6 has priority number assigned as 4 hence it will be executed just after P3.
Proce Priorit Arriv Bur Completi Turnarou Waitin Respon
ss Id y al st on Time nd Time g se Time
After
P6, P4
Time Tim Time
has the e
least

1 2 0 3 3 3 0 0

2 6 2 5 18 16 11 13

3 3 1 4 7 6 2 3

4 5 4 2 13 9 7 11

5 7 6 9 27 21 12 18

6 4 5 4 11 6 2 7

7 10 7 10 37 30 18 27

priority number among the available processes; it will get executed for the whole burst time.
Since all the jobs are available in the ready queue hence All the Jobs will get executed according to their priorities. If two
jobs have similar priority number assigned to them, the one with the least arrival time will be executed.

Avg Waiting Time = (0+11+2+7+12+2+18)/7 = 52/7 units


From the GANTT Chart prepared, we can determine the completion time of every process. The turnaround time, waiting
time and response time will be determined.

1. Turn Around Time = Completion Time - Arrival Time


2. Waiting Time = Turn Around Time - Burst Time

Preemptive Priority Scheduling


In Preemptive Priority Scheduling, at the time of arrival of a process in the ready queue, its Priority is compared with the
priority of the other processes present in the ready queue as well as with the one which is being executed by the CPU at
that point of time. The One with the highest priority among all the available processes will be given the CPU next.
The difference between preemptive priority scheduling and non preemptive priority scheduling is that, in the preemptive
priority scheduling, the job which is being executed can be stopped at the arrival of a higher priority job.
Once all the jobs get available in the ready queue, the algorithm will behave as non-preemptive priority scheduling,
which means the job scheduled will run till the completion and no preemption will be done.

Example
Process Id Priority Arrival Time Burst Time

1 2(L) 0 1

2 6 1 7

3 3 2 3

4 5 3 6

5 4 4 5

6 10(H) 5 15

7 9 15 8
There are 7 processes P1, P2, P3, P4, P5, P6 and P7 given. Their respective priorities, Arrival Times and Burst times are
given in the table below.

GANTT chart PreparationAt time 0, P1 arrives with the burst time of 1 units and priority 2.
Since no other process is available hence this will be scheduled till next job arrives or its completion (whichever is
lesser).

At time 1, P2 arrives. P1 has completed its execution and no other process is available at this time hence the Operating
system has to schedule it regardless of the priority assigned to it.

The Next process P3 arrives at time unit 2, the priority of P3 is higher to P2. Hence the execution of P2 will be stopped
and P3 will be scheduled on the CPU.

During the execution of P3, three more processes P4, P5 and P6 becomes available. Since, all these three have the
priority lower to the process in execution so PS can't preempt the process. P3 will complete its execution and then P5
will be scheduled with the priority highest among the available processes.
Meanwhile the execution of P5, all the processes got available in the ready queue. At this point, the algorithm will start
behaving as Non Preemptive Priority Scheduling. Hence now, once all the processes get available in the ready queue, the
OS just took the process with the highest priority and execute that process till completion. In this case, P4 will be
scheduled and will be executed till the completion.

Since P4 is completed, the other process with the highest priority available in the ready queue is P2. Hence P2 will be
scheduled next.

P2 is given the CPU till the completion. Since its remaining burst time is 6 units hence P7 will be scheduled after this.

The only remaining process is P6 with the least priority, the Operating System has no choice unless of executing it. This
will be executed at the last.
The Completion Time of each process is determined with the help of GANTT chart. The turnaround time and the waiting
time can be calculated by the following formula.

1. Turnaround Time = Completion Time - Arrival Time


2. Waiting Time = Turn Around Time - Burst Time

Proces Priority Arrival Burst Completion Turn Waiting Time


s Id Time Time Time aroun
d Time

1 2 0 1 1 1 0

2 6 1 7 22 21 14

3 3 2 3 5 3 0

4 5 3 6 16 13 7

5 4 4 5 10 6 1

6 10 5 15 45 40 25

7 9 6 8 30 24 16

Avg Waiting Time = (0+14+0+7+1+25+16)/7 = 63/7 = 9 units


What is a Thread?
A thread is a path of execution within a process. A process can contain multiple threads.
Why Multithreading?
A thread is also known as lightweight process. The idea is to achieve parallelism by dividing a
process into multiple threads. For example, in a browser, multiple tabs can be different threads.
MS Word uses multiple threads: one thread to format the text, another thread to process inputs,
etc. More advantages of multithreading are discussed below
Process vs Thread?
The primary difference is that threads within the same process run in a shared memory space,
while processes run in separate memory spaces.
Threads are not independent of one another like processes are, and as a result threads share with
other threads their code section, data section, and OS resources (like open files and signals).
But, like process, a thread has its own program counter (PC), register set, and stack space.
Advantages of Thread over Process
1. Responsiveness: If the process is divided into multiple threads, if one thread completes its
execution, then its output can be immediately returned.
2. Faster context switch: Context switch time between threads is lower compared to process
context switch. Process context switching requires more overhead from the CPU.
3. Effective utilization of multiprocessor system: If we have multiple threads in a single process,
then we can schedule multiple threads on multiple processor. This will make process execution
faster.
4. Resource sharing: Resources like code, data, and files can be shared among all threads
within a process.
Note: stack and registers can’t be shared among the threads. Each thread has its own stack and
registers.
5. Communication: Communication between multiple threads is easier, as the threads shares
common address space. while in process we have to follow some specific communication
technique for communication between two process.

7. Enhanced throughput of the system: If a process is divided into multiple threads, and
each thread function is considered as one job, then the number of jobs completed per unit
of time is increased, thus increasing the throughput of the system.
8.
Types of Threads
There are two types of threads.
User Level Thread
Kernel Level Thread
Threads and its types in Operating System
Thread is a single sequence stream within a process. Threads have same properties as of the
process so they are called as light weight processes. Threads are executed one after another but
gives the illusion as if they are executing in parallel. Each thread has different states. Each thread
has
1. A program counter
2. A register set
3. A stack space
Threads are not independent of each other as they share the code, data, OS resources etc.
Similarity between Threads and Processes –
 Only one thread or process is active at a time
 Within process both execute sequentiall
 Both can create children
Differences between Threads and Processes –
 Threads are not independent, processes are.
 Threads are designed to assist each other, processes may or may not do it

Types of Threads:

User Level thread (ULT) –


Is implemented in the user level library, they are not created using the system calls. Thread
switching does not need to call OS and to cause interrupt to Kernel. Kernel doesn’t know about
the user level thread and manages them as if they were single-threaded processes.
Advantages of ULT –
 Can be implemented on an OS that does’t support multithreading.
 Simple representation since thread has only program counter, register set, stack space.
 Simple to create since no intervention of kernel.
 Thread switching is fast since no OS calls need to be made.
Disadvantages of ULT –
 No or less co-ordination among the threads and Kernel.
 If one thread causes a page fault, the entire process blocks.
2. Kernel Level Thread (KLT) –
Kernel knows and manages the threads. Instead of thread table in each process, the kernel
itself has thread table (a master one) that keeps track of all the threads in the system. In
addition kernel also maintains the traditional process table to keep track of the processes. OS
kernel provides system call to create and manage threads.
Advantages of KLT –
 Since kernel has full knowledge about the threads in the system, scheduler may decide to
give more time to processes having large number of threads.
 Good for applications that frequently block.
Disadvantages of KLT –
 Slow and inefficient.
 It requires thread control block so it is an overhead.

A thread is a path which is followed during a program’s execution. Majority of programs written
now a days run as a single thread.Lets say, for example a program is not capable of reading
keystrokes while making drawings. These tasks cannot be executed by the program at the same
time. This problem can be solved through multitasking so that two or more tasks can be executed
simultaneously.
Multitasking is of two types: Processor based and thread based. Processor based multitasking is
totally managed by the OS, however multitasking through multithreading can be controlled by the
programmer to some extent.
The concept of multi-threading needs proper understanding of these two terms – a process and
a thread. A process is a program being executed. A process can be further divided into
independent units known as threads.
A thread is like a small light-weight process within a process. Or we can say a collection of
threads is what is known as a process.

Applications –
Threading is used widely in almost every field. Most widely it is seen over the internet now days
where we are using transaction processing of every type like recharges, online transfer, banking
etc. Threading is a segment which divide the code into small parts that are of very light weight
and has less burden on CPU memory so that it can be easily worked out and can achieve goal in
desired field. The concept of threading is designed due to the problem of fast and regular changes
in technology and less the work in different areas due to less application. Then as says “need is
the generation of creation or innovation” hence by following this approach human mind develop
the concept of thread to enhance the capability of programming.

Multi Threading Models in Process Management


Many operating systems support kernel thread and user thread in a combined way. Example of
such system is Solaris. Multi threading model are of three types.
Many to many model.
Many to one model.
one to one model.
Many to Many Model
In this model, we have multiple user threads multiplex to same or lesser number of kernel level
threads. Number of kernel level threads are specific to the machine, advantage of this model is if
a user thread is blocked we can schedule others user thread to other kernel thread. Thus, System
doesn’t block if a particular thread is blocked.

Many to One Model

In this model, we have multiple user threads mapped to one kernel thread. In this model when a
user thread makes a blocking system call entire process blocks. As we have only one kernel
thread and only one user thread can access kernel at a time, so multiple threads are not able
access multiprocessor at the same time.

One to One Model


In this model, one to one relationship between kernel and user thread. In this model multiple
thread can run on multiple processor. Problem with this model is that creating a user thread
requires the corresponding kernel thread.
Please write comments if you find anything incorrect, or you want to share more information
about the topic discussed above

Benefits of Multithreading in Operating System


The benefits of multi threaded programming can be broken down into four major categories:
1. Responsiveness –
Multithreading in an interactive application may allow a program to continue running even if
a part of it is blocked or is performing a lengthy operation, thereby increasing responsiveness
to the user.
In a non multi threaded environment, a server listens to the port for some request and when
the request comes, it processes the request and then resume listening to another request. The
time taken while processing of request makes other users wait unnecessarily. Instead a better
approach would be to pass the request to a worker thread and continue listening to port.
For example, a multi threaded web browser allow user interaction in one thread while an
video is being loaded in another thread. So instead of waiting for the whole web-page to load
the user can continue viewing some portion of the web-page.
2. Resource Sharing –
Processes may share resources only through techniques such as-
 Message Passing
 Shared Memory
Such techniques must be explicitly organized by programmer. However, threads share the
memory and the resources of the process to which they belong by default.
The benefit of sharing code and data is that it allows an application to have several threads of
activity within same address space.
3. Economy –
Allocating memory and resources for process creation is a costly job in terms of time and
space.
Since, threads share memory with the process it belongs, it is more economical to create and
context switch threads. Generally much more time is consumed in creating and managing
processes than in threads.
In Solaris, for example, creating process is 30 times slower than creating threads and context
switching is 5 times slower.
4. Scalability –
The benefits of multi-programming greatly increase in case of multiprocessor architecture,
where threads may be running parallel on multiple processors. If there is only one thread then
it is not possible to divide the processes into smaller tasks that different processors can
perform.
Single threaded process can run only on one processor regardless of how many processors are
available.
Multi-threading on a multiple CPU machine increases parallelism.

Threading Issues in OS
There are several threading issues when we are in a multithreading environment. In this
section, we will discuss the threading issues with system calls, cancellation of thread, signal
handling, thread pool and thread-specific data.

Along with the threading issues, we will also discuss how these issues can be deal or resolve
to retain the benefit of the multithreaded programming environment.

Threading Issues in OS
1. System Calls
2. Thread Cancellation
3. Signal Handling
4. Thread Pool
5. Thread Specific Data
1. The fork() and exec() System Calls
The fork() and exec() are the system calls. The fork() call creates a duplicate process of the
process that invokes fork(). The new duplicate process is called child process and process
invoking the fork() is called the parent process. Both the parent process and the child process
continue their execution from the instruction that is just after the fork().

Let us now discuss the issue with the fork() system call. Consider that a thread of the
multithreaded program has invoked the fork(). So, the fork() would create a new duplicate
process. Here the issue is whether the new duplicate process created by fork() will duplicate
all the threads of the parent process or the duplicate process would be single-threaded.

Well, there are two versions of fork() in some of the UNIX systems. Either the fork() can
duplicate all the threads of the parent process in the child process or the fork() would only
duplicate that thread from parent process that has invoked it.

Which version of fork() must be used totally depends upon the application.

Next system call i.e. exec() system call when invoked replaces the program along with all its
threads with the program that is specified in the parameter to exec(). Typically the exec()
system call is lined up after the fork() system call.

Here the issue is if the exec() system call is lined up just after the fork() system call then
duplicating all the threads of parent process in the child process by fork() is useless. As the
exec() system call will replace the entire process with the process provided to exec() in the
parameter.

In such case, the version of fork() that duplicates only the thread that invoked the fork()
would be appropriate.

2. Thread cancellation
Termination of the thread in the middle of its execution it is termed as ‘thread cancellation’.
Let us understand this with the help of an example. Consider that there is a multithreaded
program which has let its multiple threads to search through a database for some information.
However, if one of the thread returns with the desired result the remaining threads will be
cancelled.

Now a thread which we want to cancel is termed as target thread. Thread cancellation can be
performed in two ways:

Asynchronous Cancellation: In asynchronous cancellation, a thread is employed to


terminate the target thread instantly.
Deferred Cancellation: In deferred cancellation, the target thread is scheduled to check itself
at regular interval whether it can terminate itself or not.

The issue related to the target threads are listed below:

 What if the resources had been allotted to the cancel target thread?
 What if the target thread is terminated when it was updating the data, it was sharing with
some other thread.
Here the asynchronous cancellation of the thread where a thread immediately cancels the
target thread without checking whether it is holding any resources or not creates troublesome.

However, in deferred cancellation, the thread that indicates the target thread about the
cancellation, the target thread crosschecks its flag in order to confirm that it should it be
cancelled immediately or not. The thread cancellation takes place where they can be cancelled
safely such points are termed as cancellation points by Pthreads.

3. Signal Handling
Signal handling is more convenient in the single-threaded program as the signal would be
directly forwarded to the process. But when it comes to multithreaded program, the issue
arrives to which thread of the program the signal should be delivered.

Let’s say the signal would be delivered to:

 All the threads of the process.


 To some specific threads in a process.
 To the thread to which it applies
 Or you can assign a thread to receive all the signals.
Well, how the signal would be delivered to the thread would be decided, depending upon the
type of generated signal. The generated signal can be classified into two type’s synchronous
signal and asynchronous signal.

Synchronous signals are forwarded to the same process that leads to the generation of the
signal. Asynchronous signals are generated by the event external to the running process thus
the running process receives the signals asynchronously.

So if the signal is synchronous it would be delivered to the specific thread causing the
generation of the signal. If the signal is asynchronous it cannot be specified to which thread of
the multithreaded program it would be delivered. If the asynchronous signal is notifying to
terminate the process the signal would be delivered to all the thread of the process.

The issue of an asynchronous signal is resolved up to some extent in most of the


multithreaded UNIX system. Here the thread is allowed to specify which signal it can accept
and which it cannot. However, the Window operating system does not support the concept of
the signal instead it uses asynchronous procedure call (ACP) which is similar to the
asynchronous signal of the UNIX system.

UNIX allow the thread to specify which signal it can accept and which it will not whereas the
ACP is forwarded to the specific thread.

4. Thread Pool
When a user requests for a webpage to the server, the server creates a separate thread to
service the request. Although the server also has some potential issues. Consider if we do not
have a bound on the number of actives thread in a system and would create a new thread for
every new request then it would finally result in exhaustion of system resources.

We are also concerned about the time it will take to create a new thread. It must not be that
case that the time require to create a new thread is more than the time required by the thread
to service the request and then getting discarded as it would result in wastage of CPU time.

The solution to this issue is the thread pool. The idea is to create a finite amount of threads
when the process starts. This collection of threads is referred to as the thread pool. The
threads stay in the thread pool and wait till they are assigned any request to be serviced.

Whenever the request arrives at the server, it invokes a thread from the pool and assigns it the
request to be serviced. The thread completes its service and return back to the pool and wait
for the next request.

If the server receives a request and it does not find any thread in the thread pool it waits for
some or the other thread to become free and return to the pool. This much better than creating
a new thread each time a request arrives and convenient for the system that cannot handle a
large number of concurrent threads.

5. Thread Specific data


We all are aware of the fact that the threads belonging to the same process share the data of
that process. Here the issue is what if each particular thread of the process needs its own copy
of data. So the specific data associated with the specific thread is referred to as thread-
specific data.

Consider a transaction processing system, here we can process each transaction in a different
thread. To determine each transaction uniquely we will associate a unique identifier with it.
Which will help the system to identify each transaction uniquely.
As we are servicing each transaction in a separate thread. So we can use thread-specific data
to associate each thread to a specific transaction and its unique id. Thread libraries such as
Win32, Pthreads and Java support to thread-specific data.

So these are threading issues that occur in the multithreaded programming environment. We
have also seen how these issues can be resolved.

Related Terms:
1. Multithreading Models in Operating System
2. Thread Libraries in OS
3. Semaphore in Operating System
4. Multiplexing and it’s Types
5. Address Resolution Protocol (ARP)

Multiple-Processor Scheduling in Operating System


In multiple-processor scheduling multiple CPU’s are available and hence Load
Sharing becomes possible. However multiple processor scheduling is more complex as
compared to single processor scheduling. In multiple processor scheduling there are cases when
the processors are identical i.e. HOMOGENEOUS, in terms of their functionality, we can use any
processor available to run any process in the queue.

Approaches to Multiple-Processor Scheduling –

One approach is when all the scheduling decisions and I/O processing are handled by a single
processor which is called the Master Server and the other processors executes only the user
code. This is simple and reduces the need of data sharing. This entire scenario is
called Asymmetric Multiprocessing.
A second approach uses Symmetric Multiprocessing where each processor is self scheduling.
All processes may be in a common ready queue or each processor may have its own private
queue for ready processes. The scheduling proceeds further by having the scheduler for each
processor examine the ready queue and select a process to execute.

Processor Affinity –

Processor Affinity means a processes has an affinity for the processor on which it is currently
running.
When a process runs on a specific processor there are certain effects on the cache memory. The
data most recently accessed by the process populate the cache for the processor and as a result
successive memory access by the process are often satisfied in the cache memory. Now if the
process migrates to another processor, the contents of the cache memory must be invalidated for
the first processor and the cache for the second processor must be repopulated. Because of the
high cost of invalidating and repopulating caches, most of the SMP(symmetric multiprocessing)
systems try to avoid migration of processes from one processor to another and try to keep a
process running on the same processor. This is known as PROCESSOR AFFINITY.
There are two types of processor affinity:

1. Soft Affinity – When an operating system has a policy of attempting to keep a process
running on the same processor but not guaranteeing it will do so, this situation is called soft
affinity.
2. Hard Affinity – Hard Affinity allows a process to specify a subset of processors on which it
may run. Some systems such as Linux implements soft affinity but also provide some system
calls like sched_setaffinity() that supports hard affinity.

Load Balancing –

Load Balancing is the phenomena which keeps the workload evenly distributed across all
processors in an SMP system. Load balancing is necessary only on systems where each processor
has its own private queue of process which are eligible to execute. Load balancing is unnecessary
because once a processor becomes idle it immediately extracts a runnable process from the
common run queue. On SMP(symmetric multiprocessing), it is important to keep the workload
balanced among all processors to fully utilize the benefits of having more than one processor else
one or more processor will sit idle while other processors have high workloads along with lists of
processors awaiting the CPU.
There are two general approaches to load balancing :
1. Push Migration – In push migration a task routinely checks the load on each processor and if
it finds an imbalance then it evenly distributes load on each processors by moving the
processes from overloaded to idle or less busy processors.
2. Pull Migration – Pull Migration occurs when an idle processor pulls a waiting task from a
busy processor for its execution.

Multicore Processors –

In multicore processors multiple processor cores are places on the same physical chip. Each core
has a register set to maintain its architectural state and thus appears to the operating system as a
separate physical processor. SMP systems that use multicore processors are faster and
consume less power than systems in which each processor has its own physical chip.
However multicore processors may complicate the scheduling problems. When processor
accesses memory then it spends a significant amount of time waiting for the data to become
available. This situation is called MEMORY STALL. It occurs for various reasons such as cache
miss, which is accessing the data that is not in the cache memory. In such cases the processor can
spend upto fifty percent of its time waiting for data to become available from the memory. To
solve this problem recent hardware designs have implemented multithreaded processor cores in
which two or more hardware threads are assigned to each core. Therefore if one thread stalls
while waiting for the memory, core can switch to another thread.
There are two ways to multithread a processor :
1. Coarse-Grained Multithreading – In coarse grained multithreading a thread executes on a
processor until a long latency event such as a memory stall occurs, because of the delay
caused by the long latency event, the processor must switch to another thread to begin
execution. The cost of switching between threads is high as the instruction pipeline must be
terminated before the other thread can begin execution on the processor core. Once this new
thread begins execution it begins filling the pipeline with its instructions.
2. Fine-Grained Multithreading – This multithreading switches between threads at a much
finer level mainly at the boundary of an instruction cycle. The architectural design of fine
grained systems include logic for thread switching and as a result the cost of switching
between threads is small.

Virtualization and Threading –

In this type of multiple-processor scheduling even a single CPU system acts like a multiple-
processor system. In a system with Virtualization, the virtualization presents one or more virtual
CPU to each of virtual machines running on the system and then schedules the use of physical
CPU among the virtual machines. Most virtualized environments have one host operating system
and many guest operating systems. The host operating system creates and manages the virtual
machines. Each virtual machine has a guest operating system installed and applications run
within that guest.Each guest operating system may be assigned for specific use cases,applications
or users including time sharing or even real-time operation. Any guest operating-system
scheduling algorithm that assumes a certain amount of progress in a given amount of time will be
negatively impacted by the virtualization. A time sharing operating system tries to allot 100
milliseconds to each time slice to give users a reasonable response time. A given 100 millisecond
time slice may take much more than 100 milliseconds of virtual CPU time. Depending on how
busy the system is, the time slice may take a second or more which results in a very poor
response time for users logged into that virtual machine. The net effect of such scheduling
layering is that individual virtualized operating systems receive only a portion of the available
CPU cycles, even though they believe they are receiving all cycles and that they are scheduling
all of those cycles.Commonly, the time-of-day clocks in virtual machines are incorrect because
timers take no longer to trigger than they would on dedicated CPU’s.
Virtualizations can thus undo the good scheduling-algorithm efforts of the operating systems
within virtual machines.

Thread Scheduling
Scheduling of threads involves two boundary scheduling,
 Scheduling of user level threads (ULT) to kernel level threads (KLT) via leightweight process
(LWP) by the application developer.
 Scheduling of kernel level threads by the system scheduler to perform different unique os
functions.
Leightweight Process (LWP) :
Light-weight process are threads in the user space that acts as an interface for the ULT to access
the physical CPU resources. Thread library schedules which thread of a process to run on which
LWP and how long. The number of LWP created by the thread library depends on the type of
application. In the case of an I/O bound application, the number of LWP depends on the number
of user-level threads. This is because when an LWP is blocked on an I/O operation, then to
invoke the other ULT the thread library needs to create and schedule another LWP. Thus, in an
I/O bound application, the number of LWP is equal to the number of the ULT. In the case of a
CPU bound application, it depends only on the application. Each LWP is attached to a separate
kernel-level thread.

In real-time, the first boundary of thread scheduling is beyond specifying the scheduling policy
and the priority. It requires two controls to be specified for the User level threads: Contention
scope, and Allocation domain. These are explained as following below.
1. Contention Scope :
The word contention here refers to the competition or fight among the User level threads to
access the kernel resources. Thus, this control defines the extent to which contention takes place.
It is defined by the application developer using the thread library. Depending upon the extent of
contention it is classified as Process Contention Scope and System Contention Scope.

1. Process Contention Scope (PCS) –


The contention takes place among threads within a same process. The thread library schedules
the high-prioritized PCS thread to access the resources via available LWPs (priority as
specified by the application developer during thread creation).
2. System Contention Scope (SCS) –
The contention takes place among all threads in the system. In this case, every SCS thread is
associated to each LWP by the thread library and are scheduled by the system scheduler to
access the kernel resources.
In LINUX and UNIX operating systems, the POSIX Pthread library provides a
function Pthread_attr_setscope to define the type of contention scope for a thread during its
creation.
int Pthread_attr_setscope(pthread_attr_t *attr, int scope)
The first parameter denotes to which thread within the process the scope is defined.
The second parameter defines the scope of contention for the thread pointed. It takes two
values.
PTHREAD_SCOPE_SYSTEM
PTHREAD_SCOPE_PROCESS
If the scope value specified is not supported by the system, then the function
returns ENOTSUP.
2. Allocation Domain :
The allocation domain is a set of one or more resources for which a thread is competing. In a
multicore system, there may be one or more allocation domains where each consists of one or
more cores. One ULT can be a part of one or more allocation domain. Due to this high
complexity in dealing with hardware and software architectural interfaces, this control is not
specified. But by default, the multicore system will have an interface that affects the allocation
domain of a thread.
Consider a scenario, an operating system with three process P1, P2, P3 and 10 user level threads
(T1 to T10) with a single allocation domain. 100% of CPU resources will be distributed among
all the three processes. The amount of CPU resources allocated to each process and to each thread
depends on the contention scope, scheduling policy and priority of each thread defined by the
application developer using thread library and also depends on the system scheduler. These User
level threads are of a different contention scope.
In this case, the contention for allocation domain takes place as follows,
1. Process P1:
All PCS threads T1, T2, T3 of Process P1 will compete among themselves. The PCS threads
of the same process can share one or more LWP. T1 and T2 share an LWP and T3 are
allocated to a separate LWP. Between T1 and T2 allocation of kernel resources via LWP is
based on preemptive priority scheduling by the thread library. A Thread with a high priority
will preempt low priority threads. Whereas, thread T1 of process p1 cannot preempt thread T3
of process p3 even if the priority of T1 is greater than the priority of T3. If the priority is
equal, then the allocation of ULT to available LWPs is based on the scheduling policy of
threads by the system scheduler(not by thread library, in this case).
2. Process P2:
Both SCS threads T4 and T5 of process P2 will compete with processes P1 as a whole and
with SCS threads T8, T9, T10 of process P3. The system scheduler will schedule the kernel
resources among P1, T4, T5, T8, T9, T10, and PCS threads (T6, T7) of process P3
considering each as a separate process. Here, the Thread library has no control of scheduling
the ULT to the kernel resources.
3. Process P3:
Combination of PCS and SCS threads. Consider if the system scheduler allocates 50% of
CPU resources to process P3, then 25% of resources is for process scoped threads and the
remaining 25% for system scoped threads. The PCS threads T6 and T7 will be allocated to
access the 25% resources based on the priority by the thread library. The SCS threads T8, T9,
T10 will divide the 25% resources among themselves and access the kernel resources via
separate LWP and KLT. The SCS scheduling is by the system scheduler.
Note:
For every system call to access the kernel resources, a Kernel Level thread is created and
associated to separate LWP by the system scheduler.
Number of Kernel Level Threads = Total Number of LWP
Total Number of LWP = Number of LWP for SCS + Number of LWP for PCS
Number of LWP for SCS = Number of SCS threads
Number of LWP for PCS = Depends on application developer
Here,
Number of SCS threads = 5
Number of LWP for PCS = 3
Number of SCS threads = 5
Number of LWP for SCS = 5
Total Number of LWP = 8 (=5+3)
Number of Kernel Level Threads = 8
Advantages of PCS over SCS :
 If all threads are PCS, then context switching, synchronization, scheduling everything takes
place within the userspace. This reduces system calls and achieves better performance.
 PCS is cheaper than SCS.
 PCS threads share one or more available LWPs. For every SCS thread, a separate LWP is
associated.For every system call, a separate KLT is created.
 The number of KLT and LWPs created highly depends on the number of SCS threads created.
This increases the kernel complexity of handling scheduling and synchronization. Thereby,
results in a limitation over SCS thread creation, stating that, the number of SCS threads to be
smaller than the number of PCS threads.
 If the system has more than one allocation domain, then scheduling and synchronization of
resources becomes more tedious. Issues arise when an SCS thread is a part of more than one
allocation domain, the system has to handle n number of interfaces.
The second boundary of thread scheduling involves CPU scheduling by the system scheduler.
The scheduler considers each kernel-level thread as a separate process and provides access to the
kernel resources.

Critical Section in Synchronization


Critical Section:
When more than one processes access a same code segment that segment is known as critical section. Critical section
contains shared variables or resources which are needed to be synchronized to maintain consistency of data variable.
In simple terms a critical section is group of instructions/statements or region of code that need to be executed atomically
(read this post for atomicity), such as accessing a resource (file, input or output port, global data, etc.).
In concurrent programming, if one thread tries to change the value of shared data at the same time as another thread tries
to read the value (i.e. data race across threads), the result is unpredictable.
The access to such shared variable (shared memory, shared files, shared port, etc…) to be synchronized. Few
programming languages have built-in support for synchronization.
It is critical to understand the importance of race condition while writing kernel mode programming (a device driver,
kernel thread, etc.). since the programmer can directly access and modifying kernel data structures.
A simple solution to the critical section can be thought as shown below,
acquireLock();
Process Critical Section
releaseLock();
A thread must acquire a lock prior to executing a critical section. The lock can be acquired by only one thread. There are
various ways to implement locks in the above pseudo code. Let us discuss them in future articles.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed
above.

Mutual Exclusion with Busy Waiting (Software


approach)
 Mutual exclusion is a mechanism to ensure that only one process (or person) is doing
certain things at one time, thus avoid data inconsistency. All others should be
prevented from modifying shared data until the current process finishes
 Strict Alternation (see Fig. 2.11)
o the two processes strictly alternate in entering their CR
o the integer variable turn, initially 0, keeps track of whose turn is to enter the
critical region
o busy waiting, continuously testing a variable until some value appears, a lock
that uses busy waiting is called a spin lock
o both processes are executing in their noncritical regions
o process 0 finishes its noncritical region and goes back to the top of its loop
o unfortunately, it is not permitted to enter its CR, turn is 1 and process 1 is busy
with its nonCR
o this algorithm does avoid all races
o but violates condition 3

Figure 2.11: A proposed solution to the CR problem. (a) Process 0, (b) Process 1

 Petersons's solution (see Fig. 2.12)


o does not require strict alternation
o this algorithm consists of two procedures
o before entering its CR, each process calls enter_region with its own process
number, 0 or 1
o after it has finished with the shared variables, the process calls leave_region to
allow the other process to enter
o consider the case that both processes call enter_region almost simultaneously
o both will store their process number in turn . Whichever store is done last is the
one that counts; the first one is overwritten and lost
o suppose that process 1 stores last , so turn is 1.
o when both processes come to the while statement, process 0 enters its critical
region
o process 1 loops until process 0 exists its CR
o no violation, implements mutual exclusion
o burns CPU cycles (requires busy waiting), can be extended to work for n
processes, but overhead, cannot be extended to work for an unknown number of
processes, unexpected effects (i.e.,priority inversion problem)
Figure 2.12: Peterson' solution for achieving mutual exclusion

Sleep and Wake


(Producer Consumer problem)
Let's examine the basic model that is sleep and wake. Assume that we have two system calls as sleep and wake. The
process which calls sleep will get blocked while the process which calls will get waked up.
There is a popular example called producer consumer problem which is the most popular problem simulating sleep
and wake mechanism.
The concept of sleep and wake is very simple. If the critical section is not empty then the process will go and sleep. It
will be waked up by the other process which is currently executing inside the critical section so that the process can get
inside the critical section.
In producer consumer problem, let us say there are two processes, one process writes something while the other process
reads that. The process which is writing something is called producer while the process which is reading is
called consumer.
In order to read and write, both of them are usinga buffer. The code that simulates the sleep and wake mechanism in
terms of providing the solution to producer consumer problem is shown below.

1. #define N 100 //maximum slots in buffer


2. #define count=0 //items in the buffer
3. void producer (void)
4. {
5. int item;
6. while(True)
7. {
8. item = produce_item(); //producer produces an item
9. if(count == N) //if the buffer is full then the producer will sleep
10. Sleep();
11. insert_item (item); //the item is inserted into buffer
12. countcount=count+1;
13. if(count==1) //The producer will wake up the
14. //consumer if there is at least 1 item in the buffer
15. wake-up(consumer);
16. }
17. }
18.
19. void consumer (void)
20. {
21. int item;
22. while(True)
23. {
24. {
25. if(count == 0) //The consumer will sleep if the buffer is empty.
26. sleep();
27. item = remove_item();
28. countcount = count - 1;
29. if(count == N-1) //if there is at least one slot available in the buffer
30. //then the consumer will wake up producer
31. wake-up(producer);
32. consume_item(item); //the item is read by consumer.
33. }
34. }
35. }

The producer produces the item and inserts it into the buffer. The value of the global variable count got increased at each
insertion. If the buffer is filled completely and no slot is available then the producer will sleep, otherwise it keep
inserting.
On the consumer's end, the value of count got decreased by 1 at each consumption. If the buffer is empty at any point of
time then the consumer will sleep otherwise, it keeps consuming the items and decreasing the value of count by 1.
The consumer will be waked up by the producer if there is at least 1 item available in the buffer which is to be
consumed. The producer will be waked up by the consumer if there is at least one slot available in the buffer so that the
producer can write that.
Well, the problem arises in the case when the consumer got preempted just before it was about to sleep. Now the
consumer is neither sleeping nor consuming. Since the producer is not aware of the fact that consumer is not actually
sleeping therefore it keep waking the consumer while the consumer is not responding since it is not sleeping.
This leads to the wastage of system calls. When the consumer get scheduled again, it will sleep because it was about to
sleep when it was preempted.
The producer keep writing in the buffer and it got filled after some time. The producer will also sleep at that time
keeping in the mind that the consumer will wake him up when there is a slot available in the buffer.
The consumer is also sleeping and not aware with the fact that the producer will wake him up.
This is a kind of deadlock where neither producer nor consumer is active and waiting for each other to wake them up.
This is a serious problem which needs to be addressed.

Introduction to Semaphores
In 1965, Dijkstra proposed a new and very significant technique for managing concurrent processes by
using the value of a simple integer variable to synchronize the progress of interacting processes. This
integer variable is called a semaphore. So it is basically a synchronizing tool and is accessed only
through two low standard atomic operations, wait and signal designated by P(S) and V(S) respectively.
In very simple words, the semaphore is a variable that can hold only a non-negative Integer value, shared
between all the threads, with operations wait and signal, which work as follow:

P(S): if S >= 1 then S := S - 1

else <block and enqueue the process>;

V(S): if <some process is blocked on the queue>

then <unblock a process>

else S := S + 1;

The classical definitions of wait and signal are:


 Wait: This operation decrements the value of its argument S, as soon as it would become non-
negative(greater than or equal to 1). This Operation mainly helps you to control the entry of a task
into the critical section. In the case of the negative or zero value, no operation is
executed. wait() operation was originally termed as P; so it is also known as P(S) operation. The
definition of wait operation is as follows:

wait(S)

while (S<=0);//no operation

S--;

Note:
When one process modifies the value of a semaphore then, no other process can simultaneously modify
that same semaphore's value. In the above case the integer value of S(S<=0) as well as the possible
modification that is S-- must be executed without any interruption.
 Signal: Increments the value of its argument S, as there is no more process blocked on the queue.
This Operation is mainly used to control the exit of a task from the critical
section.signal() operation was originally termed as V; so it is also known as V(S) operation. The
definition of signal operation is as follows:

signal(S)

S++;

Also, note that all the modifications to the integer value of semaphore in the wait() and signal() operations
must be executed indivisibly.

Properties of Semaphores

1. It's simple and always have a non-negative integer value.


2. Works with many processes.
3. Can have many different critical sections with different semaphores.
4. Each critical section has unique access semaphores.
5. Can permit multiple processes into the critical section at once, if desirable.
We will now cover the types of semaphores in the Operating system;

Types of Semaphores

Semaphores are mainly of two types in Operating system:


1. Binary Semaphore:
It is a special form of semaphore used for implementing mutual exclusion, hence it is often called
a Mutex. A binary semaphore is initialized to 1 and only takes the values 0 and 1 during the
execution of a program. In Binary Semaphore, the wait operation works only if the value of
semaphore = 1, and the signal operation succeeds when the semaphore= 0. Binary Semaphores are
easier to implement than counting semaphores.
2. Counting Semaphores:
These are used to implement bounded concurrency. The Counting semaphores can range over
an unrestricted domain. These can be used to control access to a given resource that consists of a
finite number of Instances. Here the semaphore count is used to indicate the number of available
resources. If the resources are added then the semaphore count automatically gets incremented and
if the resources are removed, the count is decremented. Counting Semaphore has no mutual
exclusion.
Example of Use

Here is a simple step-wise implementation involving declaration and usage of semaphore.

Shared var mutex: semaphore = 1;

Process i

begin

P(mutex);

execute CS;

V(mutex);

End;

Advantages of Semaphores

Benefits of using Semaphores are as given below:


 With the help of semaphores, there is a flexible management of resources.
 Semaphores are machine-independent and they should be run in the machine-independent code of
the microkernel.
 Semaphores do not allow multiple processes to enter in the critical section.
 They allow more than one thread to access the critical section.
 As semaphores follow the mutual exclusion principle strictly and these are much more efficient
than some other methods of synchronization.
 No wastage of resources in semaphores because of busy waiting in semaphores as processor time
is not wasted unnecessarily to check if any condition is fulfilled in order to allow a process to
access the critical section.

Disadvantages of Semaphores

 One of the biggest limitations is that semaphores may lead to priority inversion; where low
priority processes may access the critical section first and high priority processes may access the
critical section later.
 To avoid deadlocks in the semaphore, the Wait and Signal operations are required to be executed
in the correct order.
 Using semaphores at a large scale is impractical; as their use leads to loss of modularity and this
happens because the wait() and signal() operations prevent the creation of the structured layout for
the system.
 Their use is not enforced but is by convention only.
 With improper use, a process may block indefinitely. Such a situation is called Deadlock. We will
be studying deadlocks in detail in coming lessons.

Mutex:-
A mutex is a binary variable whose purpose is to provide locking mechanism. It is used to provide
mutual exclusion to a section of code, means only one process can work on a particular code section at
a time.
There is misconception that binary semaphore is same as mutex variable but both are different in the
sense that binary semaphore apart from providing locking mechanism also provides two atomic
operation signal and wait, means after releasing resource semaphore will provide signaling mechanism
for the processes who are waiting for the resource.
Mutex is locking mechanism in OS
difference between mutex and semaphore:-
1. Mutex is used for thread but semaphore is used for process.
2.mutex is work in userspace but semaphore is work in kernal space.
3.mutex is locking mechanism ownership mathead but seamphore is signalling mechanism/didn't
ownership.
4.thread to thread mutex is used but process to process locking mechanism semaphore is used.
The full form of Mutex is Mutual Exclusion Object. It is a special type of binary semaphore which used
for controlling access to the shared resource. It includes a priority inheritance mechanism to avoid
extended priority inversion problems. It allows current higher priority tasks to be kept in the blocked state
for the shortest time possible. However, priority inheritance does not correct priority- inversion but only
minimizes its effect.

KEY DIFFERENCE
 Mutex is a locking mechanism whereas Semaphore is a signaling mechanism
 Mutex is just an object while Semaphore is an integer
 Mutex has no subtype whereas Semaphore has two types, which are counting
semaphore and binary semaphore.
 Semaphore supports wait and signal operations modification, whereas Mutex is
only modified by the process that may request or release a resource.
 Semaphore value is modified using wait () and signal () operations, on the other
hand, Mutex operations are locked or unlocked.
Use of Semaphore
In the case of a single buffer, we can separate the 4 KB buffer into four 1 KB buffers. Semaphore can be
associated with these four buffers. This allows users and producers to work on different buffers at the
same time.
Use of Mutex
A mutex provides mutual exclusion, which can be either producer or consumer that can have the key
(mutex) and proceed with their work. As long as producer fills buffer, the user needs to wait, and vice
versa. In Mutex lock, all the time, only a single thread can work with the entire buffer.
Difference between Semaphore vs. Mutex

Parameters Semaphore Mutex

Mechanism It is a type of signaling mechanism. It is a locking mechanism.

Data Type Semaphore is an integer variable. Mutex is just an object.

It is modified only by the process that m


Modification The wait and signal operations can modify a semaphore.
release a resource.

If no resource is free, then the process requires a resource If it is locked, the process has to wait. T
Resource
that should execute wait operation. It should wait until the should be kept in a queue. This needs to
management
count of the semaphore is greater than 0. only when the mutex is unlocked.

You can have multiple program threads


Thread You can have multiple program threads.
not simultaneously.

Value can be changed by any process releasing or obtaining Object lock is released only by the proce
Ownership
the resource. obtained the lock on it.

Types of Semaphore are counting semaphore and binary


Types Mutex has no subtypes.
semaphore.

Semaphore value is modified using wait () and signal ()


Operation Mutex object is locked or unlocked.
operation.

It is occupied if all resources are being used and the process In case if the object is already locked, th
Resources
requesting for resource performs wait () operation and requesting resources waits and is queued
Occupancy
blocks itself until semaphore count becomes >1. system before lock is released.

Common Facts about Mutex and Semaphore


Here, are few common facts about Mutex and Semaphore:
 Only one task can acquire the mutex. So, there is ownership associated with a mutex, and only the
owner can release the mutex.
 The reasons for using mutex and semaphore are different maybe because of similarity in their
implementation, a mutex would be referred to as binary semaphore.
 One highly known misconception is that Mutexes and Semaphores are almost same, with the only
difference being that a Mutex is capable of counting to 1, while Semaphores able to count from 0
to N.
 There is always uncertainty between binary semaphore and mutex. You may hear that a mutex is a
binary semaphore, which is not correct.
Advantages of Semaphore
Here, are pros/benefits of using Semaphore:
 It allows more than one thread to access the critical section
 Semaphores are machine-independent.
 Semaphores are implemented in the machine-independent code of the microkernel.
 They do not allow multiple processes to enter the critical section.
 As there is busy waiting in semaphore, there is never a wastage of process time and resources.
 They are machine-independent, which should be run in the machine-independent code of the
microkernel.
 They allow flexible management of resources.

Advantages of Mutex
Here, are important pros/benefits of Mutex
 Mutexes are just simple locks obtained before entering its critical section and then releasing it.
 Since only one thread is in its critical section at any given time, there are no race conditions, and
data always remain consistent.
Disadvantage of Semaphores
Here, are cons/drawback of semaphore
 One of the biggest limitations of a semaphore is priority inversion.
 The operating system has to keep track of all calls to wait and signal semaphore.
 Their use is never enforced, but it is by convention only.
 In order to avoid deadlocks in semaphore, the Wait and Signal operations require to be executed
in the correct order.
 Semaphore programming is a complex method, so there are chances of not achieving mutual
exclusion.
 It is also not a practical method for large scale use as their use leads to loss of modularity.
 Semaphore is more prone to programmer error.
 It may cause deadlock or violation of mutual exclusion due to programmer error.

Disadvantages of Mutex
Here, are cons/drawback of Mutex
 If a thread obtains a lock and goes to sleep or it is preempted, then the other thread may not able to
move forward. This may lead to starvation.
 It can't be locked or unlocked from a different context than the one that acquired it.
 Only one thread should be allowed in the critical section at a time.
 The normal implementation may lead to busy waiting state, which wastes CPU time.

Monitors in Operating System


by admin | Sep 26, 2020 | Operating System | 0 comments
Monitors in Operating System
Monitors are used for process synchronization. With the help of programming languages, we can use a
monitor to achieve mutual exclusion among the processes. Example of monitors: Java Synchronized
methods such as Java offers notify() and wait() constructs.
In other words, monitors are defined as the construct of programming language, which helps in controlling
shared data access.
The Monitor is a module or package which encapsulates shared data structure, procedures, and the
synchronization between the concurrent procedure invocations.
Characteristics of Monitors.
1. Inside the monitors, we can only execute one process at a time.
2. Monitors are the group of procedures, and condition variables that are merged together in a special type of
module.
3. If the process is running outside the monitor, then it cannot access the monitor’s internal variable. But a
process can call the procedures of the monitor.
4. Monitors offer high-level of synchronization
5. Monitors were derived to simplify the complexity of synchronization problems.
6. There is only one process that can be active at a time inside the monitor.
Components of Monitor
There are four main components of the monitor:
1. Initialization
2. Private data
3. Monitor procedure
4. Monitor entry queue
Initialization: – Initialization comprises the code, and when the monitors are created, we use this code exactly
once.
Private Data: – Private data is another component of the monitor. It comprises all the private data, and the
private data contains private procedures that can only be used within the monitor. So, outside the monitor,
private data is not visible.
Monitor Procedure: – Monitors Procedures are those procedures that can be called from outside the monitor.
Monitor Entry Queue: – Monitor entry queue is another essential component of the monitor that includes all
the threads, which are called procedures.

Syntax of monitor
Condition Variables
There are two types of operations that we can perform on the condition variables of the monitor:
1. Wait
2. Signal
3. Suppose there are two condition variables
4. sa
5. Wait Operation
6. a.wait(): – The process that performs wait operation on the condition variables are suspended and
locate the suspended process in a block queue of that condition variable.
7. Signal Operation
8. a.signal() : – If a signal operation is performed by the process on the condition variable, then a chance
is provided to one of the blocked processes.
9. Advantages of Monitor
10. It makes the parallel programming easy, and if monitors are used, then there is less error-prone as
compared to the semaphore.
11. condition a, b // Declaring variable

Difference between Monitors and Semaphore

Monitors Semaphore

In semaphore, we can use condition variables anywhere in


We can use condition variables only in the
the program, but we cannot use conditions variables in a
monitors.
semaphore.

In monitors, wait always block the caller. In semaphore, wait does not always block the caller.

The monitors are comprised of the shared


The semaphore S value means the number of shared
variables and the procedures which operate the
resources that are present in the system.
shared variable.

Condition variables are present in the monitor. Condition variables are not present in the semaphore.
Barrier

In parallel computing, a barrier is a type of synchronization method. A barrier for a group of threads or processes in
the source code means any thread/process must stop at this point and cannot proceed until all other
threads/processes reach this barrier.

Many collective routines and directive-based parallel languages impose implicit barriers. For example, a parallel do
loop in Fortran with OpenMP will not be allowed to continue on any thread until the last iteration is completed.
This is in case the program relies on the result of the loop immediately after its completion. In message passing,
any global communication (such as reduction or scatter) may imply a barrier.

Dynamic barriers
Classic barrier constructs define the set of participating processes/threads statically. This is usually done either at
program startup or when a barrier like the Pthreads barrier is instantiated. This restricts the possible applications for
which barriers can be used.

To support more dynamic programming paradigms like fork/join parallelism, the sets of participants have to be
dynamic. Thus, the set of processes/threads participating in a barrier operation needs to be able to change over
time. X10* introduced the concept of clocks for that purpose, which provide a dynamic barrier semantic. Building
on clocks, phasers have been proposed to add even more flexibility to barrier synchronization. With phasers it is
possible to express data dependencies between the participating processes explicitly to avoid unnecessary over-
synchronization.

Processor and compiler barriers


Memory barrier is a class of instructions which cause a processor to enforce an ordering constraint on memory
operations issued before and after the barrier instruction.

A barrier can also be a high-level programming language statement which prevents the compiler from reordering
other operations over the barrier statement during optimization passes. Such statements can potentially generate
processor barrier instructions. Different classes of barrier exist and may apply to a specific set of operations only.

Message passing:
Process communication is the mechanism provided by the operating system that allows processes to
communicate with each other. This communication could involve a process letting another process know
that some event has occurred or transferring of data from one process to another. One of the models of
process communication is the message passing model.
Message passing model allows multiple processes to read and write data to the message queue without
being connected to each other. Messages are stored on the queue until their recipient retrieves them.
Message queues are quite useful for interprocess communication and are used by most operating systems.
A diagram that demonstrates message passing model of process communication is given as follows −

In the above diagram, both the processes P1 and P2 can access the message queue and store and retrieve
data.

Advantages of Message Passing Model


Some of the advantages of message passing model are given as follows −
 The message passing model is much easier to implement than the shared memory model.
 It is easier to build parallel hardware using message passing model as it is quite tolerant of higher
communication latencies.
Disadvantage of Message Passing Model
The message passing model has slower communication than the shared memory model because the
connection setup takes time.

Classical IPC Problems


1. Dining Philosophers Problem
2. The Readers and Writers Problem
3. The Sleeping Barber Problem
1. Dining philosophers problems:
There are N philosphers sitting around a circular table eating spaghetti and discussing philosphy. The
problem is that each philosopher needs 2 forks to eat, and there are only N forks, one between each 2
philosophers. Design an algorithm that the philosophers can follow that insures that none starves as
long as each philosopher eventually stops eating, and such that the maximum number of philosophers
can eat at once.
• Philosophers eat/think
• Eating needs 2 forks
• Pick one fork at a time
• How to prevent deadlock

The problem was designed to illustrate the problem of avoiding deadlock, a system state in which no
progress is possible.
One idea is to instruct each philosopher to behave as follows:
• think until the left fork is available; when it is, pick it up
• think until the right fork is available; when it is, pick it up
• eat
• put the left fork down
• put the right fork down
• repeat from the start
This solution is incorrect: it allows the system to reach deadlock. Suppose that all five philosophers
take their left forks simultaneously. None will be able to take their right forks, and there will be a
deadlock.
We could modify the program so that after taking the left fork, the program checks to see if the right
fork is available. If it is not, the philosopher puts down the left one, waits for some time, and then
repeats the whole process. This proposal too, fails, although for a different reason. With a little bit of
bad luck, all the philosophers could start the algorithm simultaneously, picking up their left forks,
seeing that their right forks were not available, putting down their left forks, waiting, picking up their
left forks again simultaneously, and so on, forever. A situation like this, in which all the programs
continue to run indefinitely but fail to make any progress is called starvation

The solution presented below is deadlock-free and allows the maximum parallelism for an arbitrary
number of philosophers. It uses an array, state, to keep track of whether a philosopher is eating,
thinking, or hungry (trying to acquire forks). A philosopher may move into eating state only if neither
neighbor is eating. Philosopher i's neighbors are defined by the macros LEFT and RIGHT. In other
words, if i is 2, LEFT is 1 and RIGHT is 3.

Solution:
#define N 5 /* number of philosophers */
#define LEFT (i+N-1)%N /* number of i's left neighbor */
#define RIGHT (i+1)%N /* number of i's right neighbor */
#define THINKING 0 /* philosopher is thinking */
#define HUNGRY 1 /* philosopher is trying to get forks */
#define EATING 2 /* philosopher is eating */
typedef int semaphore; /* semaphores are a special kind of int */
int state[N]; /* array to keep track of everyone's state */
semaphore mutex = 1; /* mutual exclusion for critical regions */
semaphore s[N]; /* one semaphore per philosopher */
void philosopher(int i) /* i: philosopher number, from 0 to N1 */
{
while (TRUE){ /* repeat forever */
think(); /* philosopher is thinking */
take_forks(i); /* acquire two forks or block */
eat(); /* yum-yum, spaghetti */
put_forks(i); /* put both forks back on table */
}
}
void take_forks(int i) /* i: philosopher number, from 0 to N1 */
{
down(&mutex); /* enter critical region */
state[i] = HUNGRY; /* record fact that philosopher i is hungry */
test(i); /* try to acquire 2 forks */
up(&mutex); /* exit critical region */
down(&s[i]); /* block if forks were not acquired */
}
void put_forks(i) /* i: philosopher number, from 0 to N1 */
{
down(&mutex); /* enter critical region */
state[i] = THINKING; /* philosopher has finished eating */
test(LEFT); /* see if left neighbor can now eat */
test(RIGHT); /* see if right neighbor can now eat */
up(&mutex); /* exit critical region */
}
void test(i) /* i: philosopher number, from 0 to N1* /
{
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING) {
state[i] = EATING;
up(&s[i]);
}
}

Readers Writer problems:


The dining philosophers problem is useful for modeling processes that are competing for exclusive
access to a limited number of resources, such as I/O devices. Another famous problem is the readers
and writers problem which models access to a database (Courtois et al., 1971). Imagine, for example,
an airline reservation system, with many competing processes wishing to read and write it. It is
acceptable to have multiple processes reading the database at the same time, but if one process is
updating (writing) the database, no other process may have access to the database, not even a reader.
The question is how do you program the readers and the writers? One solution is shown below.

Solution to Readers Writer problems


typedef int semaphore; /* use your imagination */
semaphore mutex = 1; /* controls access to 'rc' */
semaphore db = 1; /* controls access to the database */
int rc = 0; /* # of processes reading or wanting to */
void reader(void)
{
while (TRUE){ /* repeat forever */
down(&mutex); /* get exclusive access to 'rc' */
rc = rc + 1; /* one reader more now */
if (rc == 1) down(&db); /* if this is the first reader ... */
up(&mutex); /* release exclusive access to 'rc' */
read_data_base(); /* access the data */
down(&mutex); /* get exclusive access to 'rc' */
rc = rc 1; /* one reader fewer now */
if (rc == 0) up(&db); /* if this is the last reader ... */
up(&mutex); /* release exclusive access to 'rc' */
use_data_read(); /* noncritical region */
}
}

You might also like