(OS) - Unit-2.2-2.5 Process Management
(OS) - Unit-2.2-2.5 Process Management
By,
Nabaraj Bahadur Negi
1
Topics Covered
• Threads
• Inter process communication(IPC)
• Implementing mutual exclusion
• Classical IPC problems
2
Thread
• A thread (or lightweight process)
• A system registers which hold its current working variables, a stack which
contains the execution history and counter that keeps track of which instruction
to execute next.
5
Figure. A multithreaded Web server
6
Figure .Multithreaded server architecture.
7
Figure .Single-threaded and multithreaded processes.
8
Multicore Programming
9
• A recent trend in computer architecture is to produce chips with
multiple cores, or CPUs on a single chip.
• A multi-threaded application running on a traditional single-core chip
would have to interleave the threads,
• On a multi-core chip, the threads could be spread across the available
cores, allowing true parallel processing.
10
Types of Threads
• User threads are supported above the kernel and are managed without kernel
support, whereas kernel threads are supported and managed directly by the
operating system.
User-level threads
• User-level threads are implemented by users and the kernel is not aware of
the existence of these threads.
• User level thread is also called many-to-one mapping thread because the
operating system maps all threads in a multithreaded process to a single
execution context. The operating system considers each multithreaded
processes as a single execution unit.
• User level thread uses space for thread scheduling. The threads are
transparent to the operating system
• User threads are implemented by users and managed entirely by the run-
time system.
• If one user level thread performs blocking operation then entire process
will be blocked.
• Implementation is by a thread library at the user level
• User level threads are created by runtime libraries that cannot execute
privileged instructions.
• User-level threads requires non-blocking systems call i.e., a multithreaded
kernel. Otherwise, entire process will blocked in the kernel, even if there
are runnable threads left in the processes. For example, if one thread
causes a page fault, the process blocks.
• Example : Java thread, POSIX threads.
12
Kernel-supported threads
• Supported by the kernel.
• Threads are constructed and controlled by system calls. The system knows
the state of each thread
• Kernel level thread support one-to-one thread mapping. Mapping requires
each user thread with kernel thread.
• Kernel level threads are implemented by Operating system. In the kernel
level thread, thread management is done by kernel.
• Implementation of kernel thread is complicated.
• Since, kernel managing threads, kernel can schedule another thread if a
given thread blocks rather than blocking the entire processes.
• Kernel level threads are slower than user level threads
• Examples: Windows XP/2000,Solaris 2,Linux,Mac OS X
13
Thread libraries: Thread libraries provide programmers with an API for
creating and managing threads.
• Thread libraries may be implemented either in user space or in kernel space.
Library entirely in user space, with no kernel support. The latter involves
system calls, and requires a kernel with thread library support.
• Three primary thread libraries:
• POSIX Ptheads: may be provided as either a user or kernel library, as
an extension to the POSIX standard.
• Win32 threads: provided as a kernel-level library on Windows systems.
• JAVA threads: Since Java generally runs on a Java Virtual
Machine, the implementation of threads is based upon whatever OS and
hardware the JVM is running on, i.e. either Pthreads or Win32 threads
depending on the system.
14
Multithreading Models
Many-to-One
• Many user-level threads mapped to
single kernel thread
• Thread management is done by the
thread library in user space
• Examples:
User responsiveness: When one thread blocks, another may handle user I/O
• But: depends on threading implementation
Resource sharing: Memory is shared (i.e., address space shared)
• Open files, sockets shared
Economy: Creating a thread is fast
• Context switching among threads may be faster
Speed: E.g., Solaris: thread creation about 30x faster than heavyweight
process creation; context switch about 5x faster with thread
Utilizing hardware parallelism: Like heavy weight processes, can also
make use of multiprocessor architectures
19
Inter-process Communication(IPC)
• Inter-process communication is used for exchanging data between multiple
threads in one or more processes or program and synchronize the data.
• There are numerous reasons for providing an environment or situation which
allows process co-operation:
• Information sharing: exchange the information
• Computation speedup: If you want a particular work to run fast, you must break
it into sub-tasks where each of them will get executed in parallel with the other
tasks.
• Modularity: Build the system in a modular way by dividing the system functions
into split processes or threads.
• Convenience: Even a single user may work on many tasks at a time. For
example, a user may be editing, formatting, printing, and compiling in parallel.
20
• There are two primary models of Interprocess Communication:
21
• In the shared memory system, the cooperating process which wants to initiate the
communication establishes a region of shared memory in its address space. The
other cooperative process which requires the shared data has to attach itself to the
address space of the initiating process.
• The process A has some data, to share with process B. Process A has to take the
initiative and establish a shared memory region in its own address space and store
the data or information to be shared in it’s shared memory region.
• Process B requires the information stored in the shared segment of the A. So,
process B has to attach itself to the shared address space of A. Now, B can read out
the data from there.
• Process A and B can exchange information or data by reading and writing data in
the shared segment of the process.
• The message-passing system shares the data by passing the messages. If a process
needs to share the data, it writes the data in the message and passes it on to the
kernel. The process that requires the shared data read it out from the kernel.
22
Race Conditions
• Process Synchronization is a mechanism that deals with the synchronization of
processes. It controls the execution of processes running concurrently to ensure that
consistent results are produced.
• The situation where two or more processes reading or writing some share data and
the final results depends on who runs precisely when are called Race conditions.
• A race condition occurs when two processes can interact and the outcome depends
on the order in which the processes execute.
• When a process wants to print a file, it enters the file name in a special spooler
directory.
• Imagine that our spooler directory has a very large number of slots, numbered 0, 1,
2, ..., each one capable of holding a file name.
• At a certain instant, slots 0 to 3 are empty (the files have already been printed) and
slots 4 to 6 are full (with the names of files queued for printing).
23
Figure .Two processes want to access shared memory at same time
• An operating system is providing printing services, “printer system process ”
picks a print job from spooler. Each job gets a job number, and this is done by
the spooler using two global variables “in” and “out”.
• Process A reads in and stores the value, 7, in a local variable called next free
slot. Just then a clock interrupt occurs and the CPU decides that process A has
run long enough, so it switches to process B.
• Process B also reads in, and also gets a 7, so it stores the name of its in slot 7
and update into be an 8. Then it goes off and does other things.
• Eventually, process A runs again, starting from the place it left off. It looks at
next free slot, finds a 7 there, and writes its file name in slot 7, erasing the
name that process B just put there. Then it computes next free slot + 1, which
is 8, and sets in to 8.
• The spooler directory is now internally consistent, so the printer daemon will
not notice anything wrong, but process B will never receive any output. 25
Critical Regions
• That part of the program where the shared memory is accessed is called the
critical region or critical section.
• Atomic action is required in a critical section i.e. only one process can
execute in its critical section at a time. All the other processes have to wait to
execute in their critical sections.
• To avoid race condition we need mutual exclusion.
• Mutual exclusion: Mechanism which makes sure that two or more processes
do not access a common resource at the same time.
• The difficulty in printer spooler occurs because process B started using one of
the shared variables before process A was finished with it. If we could arrange
matter such that no two processes were ever in there critical regions at the
same time, we could avoid race conditions.
26
Solution to Critical Section Problem:
• No two processes may be simultaneously inside their critical regions.
• No assumptions may be made about speeds or the number of CPUs.
• No process running outside its critical region may block any process.
• No process should have to wait forever to enter its critical region.
27
Requirements of Synchronization mechanisms
Mutual Exclusion
Our solution must provide mutual exclusion. By Mutual Exclusion, we mean that if one
process is executing inside critical section then the other process must not enter in the
critical section.
Progress
Progress means that if one process doesn't need to execute into critical section then it
should not stop other processes to get into the critical section.
Bounded Waiting
We should be able to predict the waiting time for every process to get into the critical
section. The process must not be endlessly waiting for getting into the critical section.
Architectural Neutrality
Our mechanism must be architectural natural. It means that if our solution is working
fine on one architecture then it should also run on the other ones as well.
Example :
• Process A enters its critical region at time T1. A little later, at time T2 process
B attempts to enter its critical region but fails because another process is
already in its critical region and we allow only one at a time.
• Process B is temporarily suspended until time T3 when A leaves its critical
region, allowing B to enter immediately. Eventually B leaves (at T4) and we
are back to the original situation with no processes in their critical regions.
30
Disabling interrupts
• Simplest solution, After entering critical region, disable all interrupts
• The CPU is only switched from process to process as a result of clock or other
interrupts, after all, and with interrupts turned off the CPU will not be
switched to another process.
• May be used inside operating system kernel when some system Structures are
to be updated, but is not recommended for Implementation of mutual
exclusion in user space.
• Advantage: process inside critical region may update shared resources
Without any risk of races
• Disadvantage: if after leaving the region interrupts are not reenabled There
will be a crash of the system. Moreover: useless in multiprocessor
Architectures.
31
Lock variables
• Software solution at user level, multiprogram med solution.
• A software solution. Considering having a single, shared lock variable,
initially 0.
• When a process wants to enter critical region, it first tests the lock.
• If the lock = 0, the process sets it to 1 and enters the critical region.
• If the lock is already 1, the process just waits until it becomes 0. Thus, a 0
means that no process is in its critical region, and a 1 means that some process
is in its critical region.
• The pseudo code of the mechanism looks like following.
Entry Section →
While (lock! = 0);
Lock = 1;
//Critical Section
Exit Section →
32
Lock =0;
Strict Alternation/Turn Variable
Figure. A proposed solution to the critical region problem. (a) Process P0. (b) Process P1. In both
cases, be sure to note the semicolons terminating the while statements.
33
• Turn Variable or Strict Alternation Approach is the software
mechanism implemented at user mode.
• It keeps track of whose turn it is to enter the critical region and
examine or update the shared memory.
• Initially, process P0 inspects turn, finds it to be 0, and enters its critical
region. Process P1 also finds it to be 0 and therefore sits in a tight loop
continually testing turn to see when it becomes 1.
• Continuously testing a variable until some value appears is called
busy waiting. It should usually be avoided, since it wastes CPU time.
A lock that uses busy waiting is called a spin lock.
• When process P0 leaves the critical region, it sets turn to 1, to allow
process P1 to enter its critical region. This way no two process can
enters critical region simultaneously. 34
Peterson’s Solution
35
• Peterson's solution is used for mutual exclusion and allowed to processes to share a
single use resource without conflict. It uses only shared memory for communication.
• Peterson's solution originally worked only with two processes, but has been generalized
for more than two.
• Initially neither process is in its critical region. Now process 0 calls enter region. It
indicates its interest by setting its array element and sets turn to 0. Since process 1 is not
interested, enter region returns immediately.
• If process 1 now makes a call to enter region, it will hang there until interested[0] goes to
FALSE, an event that happens only when process 0 calls leave region to exit the critical
region.
• Now consider the case that both process call "Enter Region" almost simultaneously.
Then both will store the process number in 'turn'. Which ever store is done last is the one
that counts the first one is overwritten and lost. Suppose that process 1 stores last, so
'turn' is 1, when both processes come to the while statement, process 0 executes it zero
times and enters its critical region.
• Process 1 loops and does not enter a critical region until process 0 exit its critical region.
36
TSL Instruction
Figure . Entering and leaving a critical region using the TSL instruction.
37
• Software solution has many problem like, high processing overhead,
logical errors etc.
• Hardware solution, multiprocess solution(n>=2), some computer
architectures offer an instruction TEST AND SET LOCK (TSL).
• TSL RX,LOCK
• (Test and Set Lock) that works as follows: it reads the contents of the
memory word LOCK into register RX and then stores a nonzero value at
the memory address LOCK.
• The operations of reading the word and storing into it are guaranteed to be
indivisible no other processor can access the memory word until the
instruction is finished.
• The CPU executing the TSL instruction locks the memory bus to prohibit
other CPUs from accessing memory until it is done.
38
• An alternative instruction to TSL is XCHG, which exchanges the contents
of two locations atomically, for example, a register and a memory word.
• All Intel x86 CPUs use XCHG instruction for low-level synchronization.
Figure . Entering and leaving a critical region using the XCHG instruction.
39
Sleep and Wakeup
• When a process is not permitted to access its critical section, it uses a system
call known as sleep, which causes that process to block. The process will not
be scheduled to run again, until another process uses the wakeup system
call.
• In most cases, wakeup is called by a process when it leaves its critical
section if any other processes have blocked.
• There is a popular example called producer consumer problem which is
the most popular problem simulating sleep and wake mechanism.
• The problem describe two processes, User and Consumer, who share a
common fixed size buffer. Producer consumer problem also known as
the "Bounded Buffer Problem" is a multi-process synchronization
problem.
• Disadvantage: wakeup signal may be lost, which leads to deadlock. 40
Producer: The producer's job is to generate a bit of data, put it into the buffer and start
again.
Consumer: The consumer is consuming the data (i.e remaining it from the buffer) one
piece at a time.
• If the buffer is empty, then a consumer should not try to access the data item from it.
Similarly, a producer should not produce any data item if the buffer is full.
• Counter: It counts the data items in the buffer. or to track whether the buffer is empty
or full. Counter is shared between two processes and updated by both.
How it works?
• Counter value is checked by consumer before consuming it.
• If counter is 1 or greater than 1 then start executing the process and updates the
counters.
• Similarly producer check the buffer for the value of Counter for adding data.
• If the counter is less than its maximum values, it means that there is some space in
41
Buffer.
Figure. The producer-consumer problem with a fatal race condition. 42
Types of mutual exclusion
• Semaphores
• Monitors
• Locks (mutexes)
• Message passing
• Bounded Buffer(Producer consumer )
43
Semaphores
• In 1965, when E. W. Dijkstra (1965) suggested using an integer variable to count
the number of wakeups saved for future use.
• Proposed variable or abstract datatype called semaphore ,A semaphore could
have the value 0, indicating that no wakeups were saved, or some positive value if
one or more wakeups were pending.
• Dijkstra proposed having two operations on semaphores, now usually called
down and up (generalizations of sleep and wakeup). he used the names P and V
instead of down/wait and up/signal.
• The down operation on a semaphore checks to see if the value is greater than 0. If
so, it decrements the value (i.e., uses up one stored wakeup) and just continues.
• If the value is 0, the process is put to sleep without completing the down for the
moment. Checking the value, changing it, and possibly going to sleep, are all
done as a single, indivisible atomic action.
44
Two operations which can be used to access and change the value of
semaphore variable.
P(semaphore s){
While(s==0); /* wait until s=0*/
S=s-1;
}
V(semaphore s){
S=s+1;
}
45
Figure. The producer-consumer problem using semaphores.
46
• This solution uses three semaphores: one called full for counting the
number of slots that are full, one called empty for counting the number of
slots that are empty, and one called mutex to make sure the producer and
consumer do not access the buffer at the same time.
• Semaphores that are initialized to 1 and used by two or more processes to
ensure that only one of them can enter its critical region at the same time
are called binary semaphores, only takes the values 0 and 1 during
execution of a program. Hence it is often called a mutex
• Counting semaphore can be used when we need to have more than one
process in the critical section at the same time.
• Counting = -∞ to +∞, Binary=0,1
• It is a very popular tool used for process synchronization.
47
Monitors
• To make it easier to write correct programs, brinch hansen (1973) and
hoare (1974) proposed a higher-level synchronization primitive called a
monitor.
• A monitor is a collection of procedures,
Variables, and data structures that are all
Grouped together in a special kind of module
Or package.
• Monitor is same as a class type: like
object of class are created, the variable
of monitor type are defined.
Figure. A monitor.
48
49
Figure . An outline of the producer-consumer problem with monitors
Mutexes
50
• A mutex is a shared variable that can be in one of two states: unlocked or
locked. Consequently, only 1 bit is required to represent it, but in practice
an integer often is used, with 0 meaning unlocked and all other values
meaning locked.
• Tw o procedures are used with mutexes. When a thread (or process) needs
access to a critical region, it calls mutex lock. If the mutex is currently
unlocked (meaning that the critical region is available), the call succeeds
and the calling thread is free to enter the critical region.
• On the other hand, if the mutex is already locked, the calling thread is
blocked until the thread in the critical region is finished and calls mutex
unlock. If multiple threads are blocked on the mutex, one of them is chosen
at random and allowed to acquire the lock.
51
Figure . Some of the Pthreads calls relating to mutexes.
54
• Indirect addressing, via some mailbox playing the role of the Intermediate
buffer. Send and receive has as an argument mailbox Address, not the
address of any particular process.
• The sender and receiver processes should share a mailbox to communicate.
55
Figure. The producer-consumer problem with N messages
56
Classical IPC Problems
57
Figure . Lunch time in the Philosophy Department.
#define N 5 /* number of philosophers */
void philosopher(int i) /* i: philosopher number, from 0 to 4 */
{
while (TRUE) {
think( ); /* philosopher is thinking */
take fork(i); /* take left for k */
take fork((i+1) % N); /* take right for k; % is modulo operator */
eat( ); /* yum-yum, spaghetti */
put fork(i); /* put left for k back on the table */
put fork((i+1) % N); /* put right for k back on the table */
}
}
60
#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 for ks */
#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 N−1 */
{
while (TRUE) { /* repeat forever */
think( ); /* philosopher is thinking */
take forks(i); /* acquire two for ks or block */
eat( ); /* yum-yum, spaghetti */
put forks(i); /* put both for ks back on table */
}
void take forks(int i) /* i: philosopher number, from 0 to N−1 */
{
down(&mutex); /* enter critical region */
state[i] = HUNGRY; /* record fact that philosopher i is hungry */
test(i); /* tr y to acquire 2 for ks */
up(&mutex); /* exit critical region */
down(&s[i]); /* block if for ks were not acquired */
}
void put forks(i) /* i: philosopher number, from 0 to N−1 */
{
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 N−1 */
{
if (state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] !=
EATING) {
state[i] = EATING;
up(&s[i]);
}
}
67
The Sleeping Barber Problem
68
Problem description:
69
• The barber shop has one barber, one barber chair, and n chairs for waiting customers,
if any, to sit on.
• If there are no customers present, the barber sits down in the barber chair and falls
asleep, as shown in the figure in the previous slide
• When a customer arrives, he has to wake up the sleeping barber. If additional
customers arrive while the barber is cutting a customer’s hair, they either sit down (if
there are empty chairs) or leave the shop (if all chairs are full).
The solution uses three semaphores:
• customers , which counts waiting customers (excluding the customer in the
barber chair, who is not waiting),
• barbers , no. of barbers (0 or 1) based on barber is idle/waiting for customers,
• mutex , which is used for mutual exclusion.
• We also need a variable, waiting , which also counts the waiting customers. It is
essentially a copy of customers .
70
#define CHAIRS 5 /* number of chairs for waiting customers */
typedef int semaphore;
semaphore customers = 0; /* number of waiting customers */
semaphore barbers = 0; /* number of barbers waiting for customers */
semaphore mutex = 1; /* for mutual exclusion */
int waiting = 0; /* customers are waiting not being haircut */
void Barber(void){
while (TRUE){
down(customers); /* go to sleep if number of customers is 0 */
down(mutex); /* acquire access to ‘waiting’ */
waiting = waiting – 1; /* decrement count of waiting customers */
up(barbers); /* one barber is now ready to cut hair */
up(mutex); /* release ‘waiting’ */
cut_hair(); /* cut hair, non-CS */
}}
71
void customer(void){
down(mutex); /* enter CS */
if (waiting < CHAIRS){
waiting = waiting + 1; /* increment count of waiting customers */
up(customers); /* wake up barber if necessary */
up(mutex); /* release access to ‘waiting’ */
down(barbers); /* wait if no free barbers */
get_haircut(); /* non-CS */
}else{
up(mutex); /* shop is full, do not wait */
}
}
72