Module 1 Process Management
Module 1 Process Management
At any given point in time, while the program is executing, this process can be
uniquely characterized by a number of elements, including the following:
Identifier: A unique identifier associated with this process, to distinguish it from all
other processes.
State: If the process is currently executing, it is in the running state.
Priority: Priority level relative to other processes.
Program counter: The address of the next instruction in the program to be
executed.
2
Memory pointers: Includes pointers to the program code and data associated with
this process, plus any memory blocks shared with other processes.
Context data: These are data that are present in registers in the processor while the
process is executing.
I/O status information: Includes outstanding I/O requests, I/O devices (e.g.,
disk drives) assigned to this process, a list of files in use by the process, and so on.
Accounting information: May include the amount of processor time and clock time
used, time limits, account numbers, and so on.
The above information is stored in a data structure known as process control block as
shown in Figure 2.1. It is created and managed by OS.
W hen a job (or process) enters a job pool, it will be in a not running state. Once it is ready
to execute and gets a processor, it will be into running state. W hen it has to wait for
any resources or for I/O, it will be paused and sent into not running state again. During
this time, another process may start running. Once the previous process is ready again,
it will be switched from not running to running. This task is shown in Figure 2.2(a).
In this model, there must be some information relating to each process like current state,
location in the memory etc. This will help OS to keep track of the process and is known as
process control block. Processes that are not running must be kept in a queue, waiting for
their turn to execute as shown in Figure 2.2(b). In this single queue, each entry is a pointer
to the process control block of a particular process. In other words, each block represents
one process here.
Process Creation: W hen a new process has to be added to the job pool, the OS builds
the data structures for managing this process and allocates address space in main
memory. These actions form the creation of a new process. The situations that will lead to
the process creation are listed in Table 2.1.
Most of the times, the OS creates the processes depending on various situations. But,
sometimes, it creates a process based on the explicit request of another process. This is
called as process spawning. W hen one process spawns another, the first process is
called as parent process and the spawned process is called as child process.
Process Termination: Every process that is created will be terminated at some moment
of time. There are several reasons for a process to get terminated as listed in Table 2.2.
To avoid this problem, it is better to split not running state into two parts viz. ready
and blocked. This model, known as five-state model is shown in Figure 2.3. The five
states of this model are explained below:
Any process has to undergo transition between these states. The possible transitions are
listed below:
Null to New: A new process is created for execution. This event may occur due to
any reasons listed in Table 2.1.
New to Ready: The OS will move a process from New state to Ready when it is
ready to take additional process. Generally, there will be a limit for a number of
processes that can be kept on a queue so as to maintain the efficiency.
Ready to Running: A scheduler or dispatcher selects one ready process for
execution.
Running to Exit: Currently running process is terminated by OS. (Refer Table 2.2
for reasons for termination).
Running to Ready: Most of the OS have a limit for a time duration for which
a process can run continuously. After that, even if it is not completed, it has to
leave
the processor for other waiting processes and has to enter a job queue.
6
Running to Blocked: If a process requests for some resources, then it will be kept
in a blocked state.
Blocked to Ready: Once a process gets the requested resources and completes
the task using those resources, it can enter into ready state.
Ready to Exit: Though this state is not shown in the diagram, it may occur.
Sometimes, a child process may be in ready state, and its parent may exit. Then, the
child process also will be exited. Or, the parent itself may terminate the child.
Blocked to Exit: A process may not get the resources that it requested or it
exceeds the waiting time.
Figure 2.4 shows the queuing discipline maintained by processes with respect to the states
mentioned in Figure 2.3.
Assume an OS without virtual memory. Then all the processes to be executed must be
loaded into main memory. Most of the processes will require I/O and hence may get
blocked. As, I/O speed is much slower than that of processor, the processor would stay idle
again. Hence, when none of the processes in the main memory is in Ready state, the OS
can swap (move) one of the blocked processes into the disk. This will form a
suspend queue. Now, any other process can be loaded into the main memory and start
execution. As disk I/O is faster, the swapping will increase the performance. W ith
the usage of swapping, one more state will be added to the process behavior model as
shown in Figure
2.5 (a).
Some of the reason for process suspension is listed in Table 2.3. It also describes
the usages by suspending the process.
8
2.10 CPU SCHEDULER
CPU scheduling is a basis of multiprogrammed OS. By switching CPU among processes,
the OS makes the computer more productive. In multiprogrammed OS, some process has
to keep running all the time in CPU without keeping it idle. This will lead to maximum CPU
utilization.
W henever the CPU becomes idle, the OS must select one of the processes in the
ready queue to be executed. The selection process is carried out by the short-term
scheduler (or CPU scheduler). The processed picked from ready queue need not be first-
come-first- out queue. There are various types like shortest job first, round robin etc.
(a) (b)
Figure 2.17(a) Alternating sequence of CPU & I/O bursts (b) Histogram of CPU burst times
10
10
Under non-preemptive scheduling, once the CPU has been allocated to a process, the
process keeps the CPU until it releases the CPU either by terminating or by switching
to the waiting state. Preemptive scheduling incurs a cost. Consider the case of two
processes sharing data. One may be in the midst of updating the data when it is
preempted and the second process is run. The second process may try to read the data,
which are currently in an inconsistent state.
2.10.3 Dispatcher
The dispatcher is the module that gives control of the CPU to the process selected by the
short-term scheduler. This function involves:
Switching context
Switching to user mode
Jumping to the proper location in the user program to resume that program
The dispatcher should be as fast as possible, because it will be invoked during
every process switch.
Example 1: The three processes P1 , P2 , and P3 arrive at a time 0 with the CPU burst time
given as below. Calculate average waiting time and average turnaround time.
Solution: Suppose, the processes arrive in the order P1, P2 , P3, then the Gantt Chart for
the schedule is –
P1 P2 P3
0 24 27 30
Turnaround time is the duration from submission of the process till its completion. Hence,
turnaround time for P1= 24
Turnaround time for P2 = 27
Turnaround time for P3 = 30
Average turnaround time = (24+27+30)/3 = 27 milliseconds
12
12
Throughput is total number of processes completed per one unit of time. Here, 30
time units were for completing 3 processes. So, for 1 time unit, the number of
processes that can be completed is 3/30. That is,
Throughput = 3/30 = 0.1
Example 2:
Assume, in the above example, the processes arrive in the order P2 , P3 , P1 then the Gantt
Chart for the schedule is –
P2 P3 P1
0 3 6 30
Now,
W aiting time for P1 = 6
W aiting time for P2 = 0
W aiting time for P3 = 3
Thus, Average waiting time = (6 + 0 + 3)/3 = 3 milliseconds
Average turnaround time = (30 + 3 + 6)/3 = 13 milliseconds
Here also, throughput = 3/30=0.1
NOTE: W e can observe that average waiting time in FCFS vary substantially if there is
a much variation in CPU burst time of the processes.
Disadvantages:
FCFS is non-preemptive, hence the average waiting time can be more.
Troublesome in time-sharing systems, where each user needs to get a share of
CPU. But, FCFS scheme will keep CPU for a longer duration.
Non-preemptive SJF Scheduling: Here, once the CPU is given to the process, it
cannot be preempted until completes its CPU burst.
Example 1: There are four processes P1 to P4 all arrived at the time 0 and burst time
is as given below. Compute average waiting time and average turnaround time.
0 3 9 16 24
Note that, if we would have used FCFS here, the average waiting time would have been
10.25 milliseconds.
Example 2: There are four processes P1 to P4 which arrived at different times as given
below. Compute average waiting time and average turnaround time.
Solution: Here, at the time 0, only process P1 is in a ready queue and hence will start
executing. But, after 2 milliseconds, the process P2 arrives with a burst time as 4.
The remaining time for P1 is 5, which is greater than time required for P2. Hence,
P1 is preempted and P2 gets CPU. After 2 more milliseconds (that is, at the time
4), P3 arrives. The burst time of P3 (1) is lesser than the remaining time of P2(2).
Hence, P2 is preempted and P3 is given a CPU. W hen P3 completes, the remaining
time of other three processes are –
P1 -- 5
P2 – 2
P4 – 4
Now, the shortest job will be getting the CPU. Hence, the Gantt chart would be –
P1 P2 P3 P2 P4 P1
0 2 4 5 7 11 16
Now, the waiting time for each process is calculated as below:
Waiting time for P1: P1 arrived at the time 0 and had been given CPU. After 2ms, it
has been preempted. Later, at the time 11, it was given a CPU again. Note that, it has
finished the task of 2ms already, hence, the waiting time would be
11 – 2 (completed portion) = 9
Waiting time for P2: P2 arrived at the time 2, and given CPU immediately. Then after 2
ms, it has been preempted. Again, CPU was given at the time 5. So, waiting time will
be
5 – 2 (arrival time) – 2 (completed time) = 1
Waiting time for P3: P3 arrived at the time 4 and was given CPU immediately. It was
not preempted during its execution. And hence, the waiting time is 0.
Waiting time for P4: P4 arrived at the time 5 and was given CPU at the time 7. Hence,
its waiting time is 2.
Example 1: There are five processes P1, P2, P3, P4 and P5 and have arrived at the time 0
in that order. The priority and burst time are as given below –
30
30
0 1 6 16 18 19
The average waiting time = (6+0+16+18+1)/5 = 8.2 milliseconds
The average turnaround time = (16+1+18+19+6)/5 = 12 ms
Throughput = 5/19 = 0.2632
Example 2: Assume there are four processes whose arrival time, burst time and
priority have been given as below. Compute average waiting time and turnaround time.
P1 P2 P4 P2 P1 P3
0 1 3 8 10 17 26
NOTE: The priority scheduling has one drawback: the lower priority processes may never
gets executed. This problem is known as starvation. As higher priority processes keeps
getting added to ready queue, the lower priority processes will find indefinite delay in
getting the CPU. In such a situation, either the process will run only when the system
becomes free, or eventually, it may crash with all un-finished processes. To solve this
problem, there is a remedy called – aging. Here, the priority of the process will
be increased as the time passes by. Hence, an initially lower priority process will
eventually becomes higher priority process and gets the CPU.
Example 1: Consider the processes P1, P2 and P3 which are arrived at the time 0. Let the
time quantum be 4 milliseconds. The burst time is given as below:
0 4 7 10 14 18 22 26 30
33
33
Note that, the burst time of processes P2 and P3 are lesser than the actual time quantum
and hence, they will give up the CPU immediately after their completion.
W aiting time for P1 = 0 (first pickup) + {10 (next pickup) – 4 (previous CPU release )} = 6
W aiting time for P2 = 4
W aiting time for P3 = 7
Average waiting time = (6+4+7)/3 = 5. 67ms
Average turnaround time = (30 +7+10)/3 = 15.67ms
Throughput = 3/30 = 0.1
Example 2: Consider the processes P1, P2, P3 and P4 which are arrived at the time 0. Let
the time quantum be 20 milliseconds. The burst time is given as below:
W aiting time for P1 = 0 (first pickup) + {77 (next pickup) – 20 (previous release)}
+ {121(next pick up) – 97 (previous release)}
= 81
W aiting time for P3 = 37 (first pickup) + {97 (next pickup) – 57 (previous release)} +
{134 (next pickup) – 117 (previous release)} +
{154 (next pickup) - 154 (previous release)}
= 94
W aiting time for P4 = 57 (first pickup) + {117 (next pickup) – 77 (previous release)}
= 97
Average waiting time = (81+20+94+97))/4 = 73 ms
Average turnaround time = (134+37+162+121)/4 =113.5 ms
Throughput = 4/162 = 0.0247
These two types have different response – time requirements and different scheduling
needs. And, foreground processes may have higher priority over background processes.
A multilevel queue scheduling algorithm partitions the ready queue into several separate
queues as shown in Figure 2.18 . Each queue has its own scheduling algorithm. Normally,
foreground queue will have Round Robin algorithm whereas, the background queue has
FCFS algorithm.
The OS design is concerned more about management of processes and threads with
respect to multiprogramming, multiprocessing and distributed processing. Concurrency is a
fundamental issue for all these areas. Concurrency includes design issues
like communication among processes, sharing of and competing for resources,
synchronization of the activities of multiple processes, and allocation of processor
time to processes. Concurrency arises in three different contexts:
Multiple applications: Multiprogramming was invented to allow processing time to
be dynamically shared among a number of active applications.
Structured applications: As an extension of the principles of modular design and
structured programming, some applications can be effectively programmed as a set
of concurrent processes.
Operating system structure: The same structuring advantages apply to systems
programs, and we have seen that operating systems are themselves often
implemented as a set of processes or threads.
In this chapter, the importance of concurrency is discussed in detail. Some of the important
key words in the study of concurrency are listed below.
36
36
One can understand the meaning of concurrency with the definition: concurrency is the
property of program, algorithm, or problem decomposability into order-independent
or partially-ordered components or units.
void echo()
{
chin = getchar();
chout = chin;
putchar(chout);
}
It is easily observed that chin and chout are global variables. The function echo()
reads one character from the keyboard and stores into chin. It is then assigned to chout.
And then it is displayed. The echo() function is global and available to all applications.
Hence, only a single copy of echo() is loaded into main memory. Sharing of such global
variables will cause certain problems in both single-processor and multi-processor systems.
To solve this problem, only one process should be allowed to invoke echo() function for
a given moment of time. That is, when P1 has invoked the function and got interrupted,
P2 may try to invoke the same function. But, P2 must be suspended and should be
made to wait. Only after P1 comes out of the echo() function, P2 must be resumed.
Thus, it is necessary to control the code for protecting shared global variable (or any other
global resources).
1 ------------------------- ------------------------
2 chin = getchar(); ------------------------
3 ------------------------- chin = getchar();
4 chout=chin; chout=chin;
5 putchar(chout); -----------------------
6 ------------------------- putchar(chout);
7 ------------------------ -----------------------
38
38
One can observe that, the global variable chin, initially read through P1, is overwritten by
P2. Here also, to avoid the problem, control the access of shared resources.
Example 1: Assume that two processes P1 and P2 are sharing a global variable a.
The process P1 has an instruction to update the value of a as –
a= 1;
The process P2 also has an instruction –
a= 2;
Both P1 and P2 will be executing their own set of instructions. Now, the value of a depends
on the order of execution of above statements. In other words, the loser of the race (the
process which executes last) will decide the value of a.
Example 2: Let there are two processes P3 and P4 sharing two global variables b and c.
Initially,
b=1 and c = 2
The process P3 has a statement –
b=b+c;
whereas, the process P4 has a statement –
c=b+c;
One can easily make out that, the final value of b and c depends on order of execution of
both of these statements. If P3 executes first,
b =3 and
c=5
On the other hand, if P4 executes first,
b= 4 and
c=3
2.15 SEMAPHORES
As discussed earlier, apart from hardware-enabled mechanism for concurrency, there
are OS and programming language mechanisms as well. Semaphore is one such
mechanism for providing concurrency. Semaphore is an integer value used for
signaling among processes. Only three operations may be performed on a
semaphore, all of which are atomic: initialize, decrement, and increment. The
decrement operation is for blocking of a process, and the increment operation is for
unblocking of a process.
The fundamental principle is: Two or more processes can cooperate by means of simple
signals, such that a process can be forced to stop at a specified place until it has received a
specific signal. For signaling, special variables called semaphores are used. To transmit a
signal via semaphore s, a process executes the primitive semSignal(s). To receive a signal
via semaphore s, a process executes the primitive semWait(s). If the corresponding
signal has not yet been transmitted, the process is suspended until the transmission takes
place.
To achieve the desired effect, we can view the semaphore as a variable that has an
integer value upon which only three operations are defined:
1. A semaphore may be initialized to a nonnegative integer value.
2. The semWait operation decrements the semaphore value. If the value becomes
negative, then the process executing the semWait is blocked. Otherwise, the
process continues execution.
3. The semSignal operation increments the semaphore value. If the resulting value is
less than or equal to zero, then a process blocked by a semWait operation, if any, is
unblocked.
40
40
The semaphore is initialized to 1. Thus, the first process that executes a semWait will be
able to enter the critical section immediately, setting the value of s to 0. Any other process
attempting to enter the critical section will find it busy and will be blocked, setting the value
of s to –1.
Let us assume that the buffer is of infinite size. Consider the code segments for producer
and consumer as given below:
Producer Consumer
while (true) while (true)
{ {
/* produce item v */; while (in <= out)
b[in] = v; /* do nothing */;
in++;
} w = b[out];
out++;
/* consume item w */;
}
The Figure 2.24 illustrates the structure of buffer b. The producer can generate items and
store them in the buffer at its own speed. Each time, an index in is incremented.
The consumer proceeds in a similar fashion but must make sure that it does not attempt to
read from an empty buffer. Hence, the consumer makes sure that the producer is ahead
of consumer (in > out).
41
41
r/consumer problem
42
42
Since, it will work in circular manner, the pointers in and out will be considered with modulo
n. Now, the situations would be –
Block on Unblock on
Producer: insert in full buffer Consumer: item inserted
Consumer: remove from empty buffer Producer: item removed
Producer Consumer
while (true) while (true)
{ {
/*produce item v */ while(in==out)
while((in+1)%n==out) //do nothing
//do nothing w=b[out]; b[in]=v;
out=(out+1)%n; in=(in+1)%n;
/*consume item w */
} }
2.16 MONITORS
The monitor is a programming-language construct that provides equivalent functionality to
that of semaphores and that is easier to control. The monitor construct has been
implemented many programming languages like Concurrent Pascal, Pascal-Plus, Java etc.
It has also been implemented as a program library. This allows programmers to put
a monitor lock on any object. For example, we can lock all linked list with one lock, or
one lock for each list or one lock for each element of every list.
Monitor must include synchronization tools for helping concurrency. For example, suppose
a process invokes the monitor and, while in the monitor, it must be blocked until some
condition is satisfied. A facility is needed by which the process is not only blocked but
releases the monitor so that some other process may enter it. Later, when the condition is
satisfied and the monitor is again available, the process needs to be resumed and allowed
to reenter the monitor at the point of its suspension.
A monitor supports synchronization by the use of condition variables that are contained
within the monitor and accessible only within the monitor. Condition variables are a
special data type in monitors, which are operated on by two functions:
cwait(c) : Suspend execution of the calling process on condition c . The monitor is
now available for use by another process.
csignal(c) : Resume execution of some process blocked after a cwait on the same
condition. If there are several such processes, choose one of them; if there is
no such process, do nothing.
Thus, we can make out that, a writer wants every other process to be blocked for its
execution; whereas, a reader need not block other processes.
The problem can be solved with the help of semaphores. Here, there are two ways: readers
having the priority and writers having priority.
As both solutions using semaphore will lead to starvation, another solution using message
passing can be adopted. In this case, there is a controller process that has access to the
shared data area. Other processes wishing to access the data area send a request
message to the controller, are granted access with an “OK” reply message, and indicate
completion of access with a “finished” message. The controller is equipped with three
mailboxes, one for each type of message (i.e. – a request, an OK, a finished) that it may
receive. The controller process services write request messages before read
request messages to give writers priority. In addition, mutual exclusion must be enforced.
2. Draw the Gantt Chart and compute average waiting time, average turnaround time
and throughput using the following algorithms:
(i) FCFS (ii) SJF (ii) RR (Quantum= 10ms)
3. Draw the Gantt Chart and compute average waiting time, average turnaround time
and throughput using the following algorithms:
(i) FCFS (ii) SJF (preemptive) (ii) Priority(preemptive) (iv) RR (Q=4)
4. Draw the Gantt Chart and compute average waiting time, average turnaround time
and throughput using the following algorithms:
(i) FCFS (ii) SJF (ii) Priority (iv) RR (Q=1)