Unit 2
Unit 2
2. Throughput –
A measure of the work done by CPU is the number of processes being executed and
completed per unit time. This is called throughput. The throughput may vary depending upon
the length or duration of processes.
3. Turnaround time –
For a particular process, an important criteria is how long it takes to execute that process. The
time elapsed from the time of submission of a process to the time of completion is known as
the turnaround time. Turn-around time is the sum of times spent waiting to get into memory,
waiting in ready queue, executing in CPU, and waiting for I/O.
4. Waiting time –
A scheduling algorithm does not affect the time required to complete the process once it starts
execution. It only affects the waiting time of a process i.e. time spent by a process waiting in
the ready queue.
5. Response time –
In an interactive system, turn-around time is not the best criteria. A process may produce some
output fairly early and continue computing new results while previous results are being output
to the user. Thus another criteria is the time taken from submission of the process of request
until the first response is produced. This measure is called response time.
Scheduling algorithms
A Process Scheduler schedules different processes to be assigned to the CPU based on particular
scheduling algorithms. There are six popular process scheduling algorithms which we are going to
discuss in this chapter −
Algorithm Evaluation
How do we select a CPU scheduling algorithm for a particular system?
There are many scheduling algorithms, each with its own parameters. As
a result, selecting an algorithm can be difficult. The first problem is
defining the criteria to be used in selecting an algorithm. Criteria are
often defined in terms of CPU utilization, response time, or throughput.
To select an algorithm, we must first define the relative importance of
these measures. Our criteria may include several measures, such as:
Deterministic Modeling
One major class of evaluation methods is analytic evaluation. Analytic
evaluation uses the given algorithm and the system workload to produce
a formula or number that evaluates the performance of the algorithm for
that workload. One type of analytic evaluation is deterministic modeling.
This method takes a particular predetermined workload and defines the
performance of each algorithm for that workload. For example, assume
that we have the workload shown below. All five processes arrive at time
0, in the order given, with the length of the CPU burst given in
milliseconds:
Deterministic modeling is simple and fast. It gives us exact numbers,
allowing us to compare the algorithms. However, it requires exact
numbers for input, and its answers apply only to those cases. The main
uses of deterministic modeling are in describing scheduling algorithms
and providing examples.
In cases where we are running the same program over and over again
and can measure the program's processing requirements exactly, we
may be able to use deterministic modeling to select a scheduling
algorithm. Furthermore, over a set of examples, deterministic modeling
may indicate trends that can then be analyzed and proved separately.
For example, it can be shown that, for the environment described (all
processes and their times available at time 0), the SJF policy will always
result in the minimum waiting time.
Queueing Models
On many systems, the processes that are run vary from day to day, so
there is no static set of processes (or times) to use for deterministic
modeling. What can be determined, however, is the distribution of CPU
and I/O bursts. These distributions can be measured and then
approximated or simply estimated. The result is a mathematical formula
describing the probability of a particular CPU burst. Commonly, this
distribution is exponential and is described by its mean. Similarly, we can
describe the distribution of times when processes arrive in the system
(the arrival-time distribution). From these two distributions, it is possible
to compute the average throughput, utilization, waiting time, and so on
for most algorithms. The computer system is described as a network of
servers.
Each server has a queue of waiting processes. The CPU is a server with
its ready queue, as is the I/O system with its device queues. Knowing
arrival rates and service rates, we can compute utilization, average
queue length, average wait time, and so on. This area of study is called
queueing-network analysis. As an example, let n be the average queue
length (excluding the process being serviced), let W be the average
waiting time in the queue, and let X be the average arrival rate for new
processes in the queue (such as three processes per second).
We expect that during the time W that a process waits, \ x W new
processes will arrive in the queue. If the system is in a steady state, then
the number of processes leaving the queue must be equal to the number
of processes that arrive. Thus, This equation, known as Little's formula, is
particularly useful because it is valid for any scheduling algorithm and
arrival distribution. We can use Little's formula to compute one of the
three variables, if we know the other two.
For example, if we know that 7 processes arrive every second (on
average), and that there are normally 14 processes in the queue, then
we can compute the average waiting time per process as 2 seconds.
Queueing analysis can be useful in comparing scheduling algorithms, but
it also has limitations. At the moment, the classes of algorithms and
distributions that can be handled are fairly limited.
The mathematics of complicated algorithms and distributions can be
difficult to work with. Thus, arrival and service distributions are often
defined in mathematically tractable —but unrealistic—ways. It is also
generally necessary to make a number of independent assumptions,
which may not be accurate. As a result of these difficulties, queueing
models are often only approximations of real systems, and the accuracy
of the computed results may be questionable.
Simulations
To get a more accurate evaluation of scheduling algorithms, we can use
simulations. Running simulations involves programming a model of the
computer system. Software data structures represent the major
components of the system. The simulator has a variable representing a
clock; as this variable's value is increased, the simulator modifies the
system state to reflect the activities of the devices, the processes, and
the scheduler. As the simulation executes, statistics that indicate
algorithm performance are gathered and printed. The data to drive the
simulation can be generated in several ways. The most common method
uses a random-number generator, which is programmed to generate
processes, CPU burst times, arrivals, departures, and so on, according to
probability distributions.
Process Synchronization
On the basis of synchronization, processes are categorized as one of the following two types:
Independent Process : Execution of one process does not affects the execution of other
processes.
Cooperative Process : Execution of one process affects the execution of other processes.
Process synchronization problem arises in the case of Cooperative process also because
resources are shared in Cooperative processes.
Race Condition
When more than one processes are executing the same code or accessing the same memory or
any shared variable in that condition there is a possibility that the output or the value of the shared
variable is wrong so for that all the processes doing the race to say that my output is correct this
condition known as a race condition. Several processes access and process the manipulations
over the same data concurrently, then the outcome depends on the particular order in which the
access takes place.
A race condition is a situation that may occur inside a critical section. This happens when the
result of multiple thread execution in the critical section differs according to the order in which the
threads execute.
Race conditions in critical sections can be avoided if the critical section is treated as an atomic
instruction. Also, proper thread synchronization using locks or atomic variables can prevent race
conditions.
In the entry section, the process requests for entry in the Critical Section.
Any solution to the critical section problem must satisfy three requirements:
Mutual Exclusion : If a process is executing in its critical section, then no other process is
allowed to execute in the critical section.
Progress : If no process is executing in the critical section and other processes are waiting
outside the critical section, then only those processes that are not executing in their remainder
section can participate in deciding which will enter in the critical section next, and the selection
can not be postponed indefinitely.
Bounded Waiting : A bound must exist on the number of times that other processes are
allowed to enter their critical sections after a process has made a request to enter its critical
section and before that request is granted.
Peterson’s Solution
Peterson’s Solution is a classical software based solution to the critical section problem.
In Peterson’s solution, we have two shared variables:
boolean flag[i] :Initialized to FALSE, initially no one is interested in entering the critical section
int turn : The process whose turn is to enter the critical section.
Synchronization Hardware
Process Synchronization refers to coordinating the execution of
processes so that no two processes can have access to the same shared
data and resources. A problem occurs when two processes running
simultaneously share the same data or variable.
There are three hardware approaches to solve process synchronization
problems:
1. Swap
2. Test() and Set()
3. Unlock and lock
Test and Set
In Test and Set the shared variable is a lock that is initialized to false.
The algorithm returns whatever value is sent to it and sets the lock to
true. Mutual exclusion is ensured here, as till the lock is set to true, other
processes will not be able to enter and the loop continues.
However, after one process is completed any other process can go in as
no queue is maintained.
Swap
In this algorithm, instead of directly setting the lock to true, the key is
first set to true and then swapped with the lock.
Similar to Test and Set, when there are no processes in the critical
section, the lock turns to false and allows other processes to enter.
Hence, mutual exclusion and progress are ensured but the bound waiting
is not ensured for the very same reason.
Unlock and Lock
In addition to Test and Set, this algorithm uses waiting[i] to check if there
are any processes in the wait. The processes are set in the ready queue
with respect to the critical section.
Unlike the previous algorithms, it doesn’t set the lock to false and checks the
ready queue for any waiting processes. If there are no processes waiting in the
ready queue, the lock is then set to false and any process can enter.
Semaphores
Semaphores are integer variables that are used to solve the critical section problem by using two atomic
operations, wait and signal that are used for process synchronization.
The definitions of wait and signal are as follows −
Wait
The wait operation decrements the value of its argument S, if it is positive. If S is negative or zero,
then no operation is performed.
Types of Semaphores
There are two main types of semaphores i.e. counting semaphores and binary semaphores. Details about
these are given as follows −
Counting Semaphores
These are integer value semaphores and have an unrestricted value domain. These semaphores
are used to coordinate the resource access, where the semaphore count is the number of
available resources. If the resources are added, semaphore count automatically incremented and
if the resources are removed, the count is decremented.
Binary Semaphores
The binary semaphores are like counting semaphores but their value is restricted to 0 and 1. The
wait operation only works when the semaphore is 1 and the signal operation succeeds when
semaphore is 0. It is sometimes easier to implement binary semaphores than counting
semaphores.
Advantages of Semaphores
Some of the advantages of semaphores are as follows −
Semaphores allow only one process into the critical section. They follow the mutual exclusion
principle strictly and are much more efficient than some other methods of synchronization.
There is no resource wastage because of busy waiting in semaphores as processor time is not
wasted unnecessarily to check if a condition is fulfilled to allow a process to access the critical
section.
Semaphores are implemented in the machine independent code of the microkernel. So they are
machine independent.
Disadvantages of Semaphores
Some of the disadvantages of semaphores are as follows −
Semaphores are complicated so the wait and signal operations must be implemented in the
correct order to prevent deadlocks.
Semaphores are impractical for last scale use as their use leads to loss of modularity. This
happens because the wait and signal operations prevent the creation of a structured layout for
the system.
Semaphores may lead to a priority inversion where low priority processes may access the critical
section first and high priority processes later.
Because the buffer pool has a maximum size, this problem is often called
the Bounded buffer problem.
Because the buffer pool has a maximum size, this problem is often called
the Bounded buffer problem.
There are five philosophers sitting around a table, in which there are
five chopsticks/forks kept beside them and a bowl of rice in the
centre, When a philosopher wants to eat, he uses two chopsticks -
one from their left and one from their right. When a philosopher
wants to think, he keeps down both chopsticks at their original
place.
The main complexity with this problem occurs from allowing more
than one reader to access the data at the same time.
There is a buffer of n slots and each slot is capable of storing one unit of
data. There are two processes running,
namely, producer and consumer, which are operating on the buffer.
A producer tries to insert data into an empty slot of the buffer. A
consumer tries to remove data from a filled slot in the buffer. As you
might have guessed by now, those two processes won't produce the
expected output if they are being executed concurrently.
Here's a Solution
do
wait(empty);
// acquire lock
wait(mutex);
// release lock
signal(mutex);
// increment 'full'
signal(full);
while(TRUE)
do
wait(full);
wait(mutex);
signal(mutex);
// increment 'empty'
signal(empty);
while(TRUE);
The consumer waits until there is atleast one full slot in the buffer.
Then it decrements the full semaphore because the number of
occupied slots will be decreased by one, after the consumer
completes its operation.
After that, the consumer acquires lock on the buffer.
Following that, the consumer completes the removal operation so
that the data from one of the full slots is removed.
Then, the consumer releases the lock.
Finally, the empty semaphore is incremented by 1, because the
consumer has just removed data from an occupied slot, thus making
it empty.
Consider there are five philosophers sitting around a circular dining table.
The dining table has five chopsticks and a bowl of rice in the middle as
shown in the below figure.
At any instant, a philosopher is either eating or thinking.
When a philosopher wants to eat, he uses two chopsticks -
one from their left and one from their right. When a
philosopher wants to think, he keeps down both chopsticks at
their original place.
while(TRUE)
wait(stick[i]);
/*
*/
wait(stick[(i+1) % 5]);
/* eat */
signal(stick[i]);
signal(stick[(i+1) % 5]);
/* think */
When a philosopher wants to eat the rice, he will wait for the
chopstick at his left and picks up that chopstick. Then he
waits for the right chopstick to be available, and then picks it
too. After eating, he puts both the chopsticks down.
But if all five philosophers are hungry simultaneously, and
each of them pickup one chopstick, then a deadlock situation
occurs because they will be waiting for another chopstick
forever. The possible solutions for this are:
while(TRUE)
wait(w);
signal(w);
Copy
And, the code for the reader process looks like this:
while(TRUE)
//acquire lock
wait(m);
read_count++;
if(read_count == 1)
wait(w);
//release lock
signal(m);
// acquire lock
wait(m);
read_count--;
if(read_count == 0)
signal(w);
// release lock
signal(m);
Copy
As seen above in the code for the writer, the writer just
waits on the w semaphore until it gets a chance to write
to the resource.
After performing the write operation, it increments w so
that the next writer can access the resource.
On the other hand, in the code for the reader, the lock is
acquired whenever the read_count is updated by a
process.
When a reader wants to access the resource, first it
increments the read_count value, then accesses the
resource and then decrements the read_count value.
The semaphore w is used by the first reader which
enters the critical section and the last reader which exits
the critical section.
The reason for this is, when the first readers enters the
critical section, the writer is blocked from the resource.
Only new readers can access the resource now.
Similarly, when the last reader exits the critical section,
it signals the writer using the w semaphore because
there are zero readers now and a writer can have the
chance to access the resource.
In the above diagram, the entry section handles the entry into the critical section. It
acquires the resources needed for execution by the process. The exit section handles
the exit from the critical section. It releases the resources and also informs the other
processes that the critical section is free.
Mutual Exclusion
Mutual exclusion implies that only one process can be inside the critical section
at any time. If any other processes require the critical section, they must wait until
it is free.
Progress
Progress means that if a process is not using the critical section, then it should
not stop any other process from accessing it. In other words, any process can
enter a critical section if it is free.
Bounded Waiting
Bounded waiting means that each process must have a limited waiting time. Itt
should not wait endlessly to access the critical section
Condition Variables:
Two different operations are performed on the condition variables of the
monitor.
Wait.
signal.
let say we have 2 condition variables
condition x, y; // Declaring variable
Wait operation
x.wait() : Process performing wait operation on any condition variable are
suspended. The suspended processes are placed in block queue of that
condition variable.
Note: Each condition variable has its unique block queue.
Signal operation
x.signal(): When a process performs signal operation on condition variable, one
of the blocked processes is given chance.
If (x block queue empty)
// Ignore signal
else
// Resume a process from block queue.
Advantages of Monitor:
Monitors have the advantage of making parallel programming easier and less
error prone than using techniques such as semaphore.
Disadvantages of Monitor:
Monitors have to be implemented as part of the programming language . The
compiler must generate code for them. This gives the compiler the additional
burden of having to know what operating system facilities are available to
control access to critical sections in concurrent processes. Some languages
that do support monitors are Java,C#,Visual Basic,Ada and concurrent Euclid.