Process Management
Process Management
Introduction:
A process is a program in execution. A process will need certain resources—such as CPU
time, memory, files, and I/O devices — to accomplish its task. These resources are allocated
to the process either when it is created or while it is executing.
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.
Process States:
As a process executes, it changes state. The state of a process is defined in part by the current
activity of that process. A process may be in one of the following states:
New: The process is being created.
Ready: The process is waiting to be assigned to a processor.
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).
Terminated: The process has finished execution.
The state diagram corresponding to these states is presented in figure below:
Fig 2: Diagram of process states
It is important to realize that only one process can be running on any processor at any instant.
Many processes may be ready and waiting, however.
Process state: The state may be new, ready, running, 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. Along with the program
counter, this state information must be saved when an interrupt occurs, to allow the
process to be continued correctly afterward.
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 items as the
value of the base and limit registers and the page tables, or the segment tables,
depending on the memory system used by the operating system.
Accounting information: This information includes the amount of CPU and real
time used, time limits, account numbers, job or process numbers, and so on. • I/O
status information. This information includes the list of I/O devices allocated to the
process, a list of open files, and so on.
Process Scheduling:
The objective of multiprogramming is to have some process running at all times, to maximize
CPU utilization. The objective of time sharing is to switch the CPU among processes so
frequently that users can interact with each program while it is running. To meet these
objectives, the process scheduler selects an available process (possibly from a set of several
available processes) for program execution on the CPU. For a single-processor system, there
will never be more than one running process. If there are more processes, the rest will have to
wait until the CPU is free and can be rescheduled.
In operating systems, scheduling is the method by which processes are given access to system
resources, primarily the CPU. Efficient scheduling is essential for optimal system
performance and user satisfaction. There are two primary types of CPU scheduling:
preemptive and non-preemptive.
Preemptive Scheduling:
Preemptive scheduling is used when a process switches from the running state to the ready
state or from the waiting state to the ready state. The resources (mainly CPU cycles) are
allocated to the process for a limited amount of time and then taken away, and the process is
again placed back in the ready queue if that process still has CPU burst time remaining. That
process stays in the ready queue till it gets its next chance to execute.
Non-Preemptive Scheduling:
Non-preemptive Scheduling is used when a process terminates, or a process switches from
running to the waiting state. In this scheduling, once the resources (CPU cycles) are allocated
to a process, the process holds the CPU till it gets terminated or reaches a waiting state. In the
case of non-preemptive scheduling does not interrupt a process running CPU in the middle of
the execution. Instead, it waits till the process completes its CPU burst time, and then it can
allocate the CPU to another process.
Round Robin and Shortest First Come First Serve and Shortest Job
Examples
Remaining Time First scheduling First
Scheduling Queues:
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.
The list of processes waiting for a particular I/O device is called a device queue. Each device
has its own device 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.
The primary distinction between these two schedulers lies in frequency of execution. The
short-term scheduler must select a new process for the CPU frequently. The long-term
scheduler executes much less frequently; minutes may separate the creation of one new
process and the next. The long-term scheduler controls the degree of multiprogramming. If
the degree of multiprogramming is stable, then the average rate of process creation must be
equal to the average departure rate of processes leaving the system. Thus, the long-term
scheduler may need to be invoked only when a process leaves the system.
It is important that the long-term scheduler make a careful selection. In general, most
processes can be described as either I/O bound or CPU bound. An I/O-bound process is one
that spends more of its time doing I/O than it spends doing computations. A CPU-bound
process, in contrast, generates I/O requests infrequently, using more of its time doing
computations. It is important that the long-term scheduler select a good process mix of I/O-
bound and CPU-bound processes. If all processes are I/O bound, the ready queue will almost
always be empty, and the short-term scheduler will have little to do. If all processes are CPU
bound, the I/O waiting queue will almost always be empty, devices will go unused, and again
the system will be unbalanced. The system with the best performance will thus have a
combination of CPU-bound and I/O-bound processes.
Context Switch:
When an interrupt occurs, CPU switch from one process to another. Then system needs to
save the current context of the process running on the CPU so that it can restore that context
when its processing is done, essentially suspending the process and then resuming it.
Generically, we perform a state save of the current state of the CPU, be it in kernel or user
mode, and then a state restore to resume operations. Switching the CPU to another process
requires performing a state save of the current process and a state restore of a different
process. This task is known as a context switch. When a context switch occurs, the kernel
saves the context of the old process in its PCB and loads the saved context of the new process
scheduled to run.
Operations on Processes:
The processes in most systems can execute concurrently, and they may be created and deleted
dynamically. Thus, these systems must provide a mechanism for process creation and
termination.
Process Creation
During the course of execution, a process may create several new processes. 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. A process is identified in memory by a unique id called process id (pid).
In general, when a process creates a child process, that child process will need certain
resources (CPU time, memory, files, I/O devices) to accomplish its task. A child process may
be able to obtain its resources directly from the operating system, or it may be constrained to
a subset of the resources of the parent process. The parent may have to partition its resources
among its children, or it may be able to share some resources (such as memory or files)
among several of its children.
When a process creates a new process, two possibilities for execution exist:
There are also two address-space possibilities for 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.
Inn UNIX, 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.
After a fork() system call, one of the two processes typically uses the exec() system call to
replace the process’s memory space with a new program.
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 deallocated by the operating system.
A parent may terminate the execution of one of its children for a variety of reasons, such as:
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.
Some systems do not allow a child to exist if its parent has terminated. In such systems, if a
process terminates (either normally or abnormally), then all its children must also be
terminated. This phenomenon, referred to as cascading termination, is normally initiated by
the operating system.
When a process terminates, its resources are deallocated by the operating system. However,
its entry in the process table must remain there until the parent calls wait(), because the
process table contains the process’s exit status. A process that has terminated, but whose
parent has not yet called wait(), is known as a zombie process. All processes transition to this
state when they terminate, but generally they exist as zombies only briefly. Once the parent
calls wait(), the process identifier of the zombie process and its entry in the process table are
released.
Now consider what would happen if a parent did not invoke wait() and instead terminated,
thereby leaving its child processes as orphans. Linux and UNIX address this scenario by
assigning the init process as the new parent to orphan processes.
Interprocess Communication:
Processes executing concurrently in the operating system may be either independent
processes or cooperating processes.
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 cores.
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, listening to music, 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: shared memory and message passing.
1. Shared Memory:
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
processes 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.
2. Message-Passing Systems:
Message passing provides a mechanism to allow processes to communicate and to
synchronize their actions without sharing the same address space. It is particularly useful in a
distributed environment, where the communicating processes may reside on different
computers connected by a network.
This scheme exhibits symmetry in addressing; that is, both the sender process and the
receiver process must name the other to communicate. A variant of this scheme employs
asymmetry in addressing. Here, only the sender names the recipient; the recipient is not
required to name the sender. In this scheme, the send() and receive() primitives are defined as
follows:
send(P, message)—Send a message to process P.
receive(id, message)—Receive a message from any process.
The variable id is set to the name of the process with which communication has taken place.
With indirect communication, the messages are sent to and received from mailboxes, or ports.
A mailbox can be viewed abstractly as an object into which messages can be placed by
processes and from which messages can be removed. Each mailbox has a unique
identification.
The send() and receive() primitives are defined as follows:
send(A, message)—Send a message to mailbox A.
receive(A, message)—Receive a message from mailbox A.
2.3 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 link’s capacity is finite, however.
If the link is full, the sender must block until space is available in the queue.
Unbounded capacity: The queue’s length is potentially infinite; thus, any number of
messages can wait in it. The sender never blocks. The zero-capacity case is sometimes
referred to as a message system with no buffering. The other cases are referred to as
systems with automatic buffering.