0% found this document useful (0 votes)
29 views41 pages

Chapter 4

Chapter 4 discusses process synchronization and inter-process communication, highlighting the importance of managing concurrency in operating systems. It outlines the benefits and challenges of concurrency, including race conditions, deadlocks, and starvation, and emphasizes the need for mutual exclusion to prevent data inconsistencies. Various methods for implementing mutual exclusion, such as busy waiting and blocking mechanisms, are also explored.

Uploaded by

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

Chapter 4

Chapter 4 discusses process synchronization and inter-process communication, highlighting the importance of managing concurrency in operating systems. It outlines the benefits and challenges of concurrency, including race conditions, deadlocks, and starvation, and emphasizes the need for mutual exclusion to prevent data inconsistencies. Various methods for implementing mutual exclusion, such as busy waiting and blocking mechanisms, are also explored.

Uploaded by

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

Chapter 4: Process Synchronization and Inter-

Process Communication
Concurrency and Its Problems

A. Basic Concept
– The most fundamental task of modern operating systems is
management of multiple processes within uniprocessor,
multiprocessor or distributed computer systems
– The fundamental design issue in the management of
multiple processes is concurrency: simultaneous execution
of multiple processes
– Concurrency arises in three different contexts
• Multiple applications: concurrently running applications
• Structured applications: an application structured as a set of
concurrent processes (threads)
• OS structure: OS implemented as a set of processes
Concurrency and Its Problems …

– Concurrency provides major benefits in processing efficiency and in


program structuring
– However, it is associated with certain problems
– To prevent problems, concurrent processes must be synchronized.
– Process synchronization is the way in which execution of concurrent
processes is executed
– It ensures that multiple processes can execute concurrently without
leading to data inconsistencies or conflicts.
– This is done by making sure that no two concurrent processes can
have access to the same shared data and resources
Concurrency and Its Problems …

B. Inter-process Communication
• There is frequent interaction among concurrently running
processes. There are three ways in which concurrent processes
interact with each other:
• Competition for Resources
It occurs when independent processes that are not intended
to work together compete for the use of the same or shared
resource, e.g. printer, memory, or file
There is no exchange of information between competing
processes
Processes are unaware of each other
Concurrency and Its Problems …

• Cooperation by Sharing Resources


It occurs when processes that are not necessarily aware of
each other use and update shared data without reference to
other processes but know that other processes may have
access to the same data
Processes must cooperate to ensure that the data they share
are properly managed
Processes are aware of each other indirectly
• Cooperation by Communication
It occurs when various processes communicate with each
other, for instance with message passing in order to provide
a way to synchronize or coordinate their various activities.
There is nothing shared between processes
Processes are aware of each other directly
Concurrency and Its Problems …

C. Concurrency Problems
• There are some serious problems associated with the interaction of
concurrently running processes:
i. Race Condition
– A situation that occurs when two or more processes are reading or
writing into some shared data and the final result depends on who
runs precisely when
– E.g. 1 Printer Spooler: when a process wants to print a file, it enters
the file name in a special spooler directory. Assume that the spooler
directory has a large number of slots, numbered 0,1,2,…
 There are two globally shared variables
 Outfile: points to the next file to be printed
 Infile: points to the next free slot in the directory
Concurrency and Its Problems …

• There were some files in the spooler directory and assume the current value
of infile is 7 and that of outfile is 3
• Assume that simultaneously process A and process B decide they want to
queue a file for printing
– Process A reads infile and stores the value 7 in its local variable (x=infile)
– An interrupt occurs and the CPU decides that process A has run long
enough so it switches to process B
– Process B reads infile and stores the value 7 in its local variable (y=infile)
– Process B stores the name of its file in slot 7 and adjusts infile to be 8
– Eventually process A runs again, it checks x and finds 7 there, and writes
its file name in slot 7, erasing the name process B just put there, it updates
infile to be 8
• The printer daemon will now print the file of process A, process B file will
never get any output
Concurrency and Its Problems …

• E.g. 2 Character echo procedure: consider the following globally shared procedure
Void echo
{
chin=getchar(); //read a character from keyboard
chout=chin;
putchar (chout); //display the character on the screen
}
• Consider two processes (P1 & P2) trying to access the procedure
– Process P1 invokes the echo procedure and is interrupted immediately after
the conclusion of getchar function (chin =x)
– Process P2 is activated and invokes the echo procedure, which runs to
conclusion, inputting an displaying a single character, y
– Process P1 is resumed. By this time the value x ihas been overwritten in chin
and therefore lost. Instead chin contains y, and is displayed twice
Concurrency and Its Problems …

ii. Deadlock
• It is the permanent blocking of a set of processes that either compete for system
resources or communicate with each other. It involves conflicting needs for
resources by two or more processes.
• It refers to a situation in which a set of two or more processes are waiting for other
members of the set to complete an operation in order to proceed, but none of the
members is able to proceed.
• E.g. Traffic deadlock: consider a situation in which four cars have arrived at a four-
way stop intersection at the same time. The four quadrants of the intersection are
the resources over which control is needed. If all four cars proceed into the
intersection, then each car controls one resource (one quadrant) but cannot
proceed because the required second resource has already been controlled by
another car. Hence deadlock will occur. The main reason for this deadlock is
because each car needs exclusive use of both resources for certain period of time
• It is a difficult phenomenon to anticipate and there are no easy general solutions to
this problem
Concurrency and Its Problems …

iii. Starvation
– It referees to the situation in which a process is
ready to execute but is continuously denied access
to a processor in deference to other processes.
– E.g. suppose that there are three processes P1, P2,
and P3 and each require periodic access to resource
R. If the operating system grants the resource to P1
and P2 alternately, P3 may indefinitely be denied
access to the resource, thus starvation may occur.
– In large part, it is a scheduling issue
Concurrency and Its Problems …

D. Mutual Exclusion
• The key to preventing race condition is to enforce mutual
exclusion: It is the ability to exclude (prohibit) all other
processes from using a shared variable or file while one
process is using it.
• Part of a program where shared resource (critical resource) is
accessed is called critical region or critical section
Concurrency and Its Problems …
Concurrency and Its Problems …

• The fundamental strategy for implementing mutual exclusion


is avoiding the situation where no two processes could ever
be in their critical regions at the same time.
• There are some basic requirements that should be met while
implementing mutual exclusion
i. No two processes may be simultaneously in their critical regions
ii. No assumptions may be made about speed or the number of
processors
iii. No process running outside its critical region may block other
processes
iv. No process should have to wait forever to enter its critical region
Implementing Mutual Exclusion with Busy Waiting

• In this section, various proposals for achieving mutual exclusion with the help of
busy waiting are examined:
A. Disabling Interrupts
– An interrupt is an event that alters the sequence in which a process executes
instruction
– In this technique, each process disables all interrupts just after entering its
critical section and re-enables them just before leaving it. With interrupts
turned off the processor will not be switched to another process
– Disadvantages
• It is unwise to give processes the power to turn off interrupts. For
instance, a process can turn off interrupts but never turn them on again in
which the whole system freezes
• If the system is multiprocessor, disabling interrupts affects only the
processor that executed the disable instruction. The other ones will
continue running and can access the shared memory.
– Disabling interrupts is often a useful technique within the operating system
itself but is not appropriate as a general mutual exclusion mechanism for user
processes.
Implementing Mutual Exclusion with Busy Waiting …

B. Lock Variables
– Assume we have a single shared (lock) variable initially set to 0
– A process enters its critical section if this variable is 0, when it enters it
sets it to 1
– If the lock is already 1, the process 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
– Disadvantages
• Suppose that one process reads the lock and sees that it is 0.
Before it can set the lock to 1, another process is scheduled, runs
and sets the lock to 1. when the first process runs again, it will also
set the lock to 1 and the two processes will be in their critical
region at the same time causing race condition
• Continuously testing a variable waiting for some value to appear is
called busy waiting. This technique wastes processor time
Implementing Mutual Exclusion with Busy Waiting …

C. Strict Alternation
– Strict alternation is shown in the program fragment below for two
processes, process 0 and process 1. This solution requires that the two
processes strictly alternate in entering their critical regions.
Implementing Mutual Exclusion with Busy Waiting …

– The integer turn, initially 0, keeps track of whose turn it is to


enter the critical region and examines or updates the shared
memory
– Initially, process 0 inspects turn, finds it to be 0, and enters its
critical region. Process 1 also finds to be 0 and therefore sits in
a tight loop continually testing turn to see when it becomes 1.
When process 0 leaves the critical region, it sets turn to 1, to
allow process 1 to enter its critical region.
– Disadvantages
• Taking turns is not a good idea when one of the processes is much
slower than the other. This situation violates condition 3 of
implementing mutual exclusions: process 0 is being blocked by a
process not in its critical region.
Implementing Mutual Exclusion with Busy Waiting …

D. Peterson’s Solution
– It is a software solution. It combines the idea of taking turns with the
idea of lock variables and warning variables. It does not require strict
alternation.
– Before using the shared variable, i.e. before entering its critical region,
each process calls enter_region procedure with its own process
number, 0 or 1 as a parameter. This call will cause it to wait, if need be,
until it is safe to enter. After it has finished with the shared variables,
the process calls leave_region procedure to indicate that it is done and
to allow the other process to enter, if it so desires. The code is shown
below:
Implementing Mutual Exclusion with Busy Waiting …
Implementing Mutual Exclusion with Busy Waiting …

• Initially, neither process is in its critical section. Now process 0 calls


enter_region. It indicates its interest by setting its array element & sets
turn to to 0. Since process 1 is not interested, enter_region returns
immediately. If process 1 now calls enter_region, it will hang there until
interested[0] goes to false, an event that only happens when process 0
calls leave_region to exit the critical region.
• Now consider the case that both processes call enter_region almost
simultaneously. Both will store their process number in turn. Whichever
store is done last is the one that counts; the first one is 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 section.
Process 1 loops and does not enter its critical section.
Implementing Mutual Exclusion with Busy Waiting …

E. TSL Instruction
– This technique requires a little help from the hardware. It uses the
hardware instruction TSL.
– TSL (Test and Set Lock) is an indivisible atomic instruction that copies
the content of a memory location into a register and stores a non-zero
value at the memory location. The operation of reading the word and
storing into it are guaranteed to be indivisible, i.e. no other processor
can access the memory word until the instruction is finished. The
processor executing the TSL instruction locks the memory bus to
prohibit other processors from accessing the memory until it is done.
– To implement mutual exclusion with TSL instruction, we use a shared
variable, lock, to coordinate access to shared memory. When lock is 0
the process may set it to 1 using TSL instruction and executes its critical
section. When it is done, the process sets lock into 0.
Implementing Mutual Exclusion with Busy Waiting …

– Before entering its critical region, a process calls enter_region, which


does busy waiting until the lock is free; then it acquires the lock and
returns. After the critical region the process calls leave_region, which
stores a 0 in lock.

Implementing Mutual Exclusion without Busy Waiting

• Both Peterson’s solution and the solution using TSL are correct, but both have the
defect of requiring busy waiting which wastes CPU time and which can also have
unexpected effects, like the priority inversion problem.
• Priority inversion problem: consider a computer with two processes, H with high
priority and L with low priority. The scheduling rules are such that H runs whenever it
is in the ready state. At a certain moment, with L in its critical region, H becomes ready
to run. H now begins busy waiting, but since L is never scheduled while H is running, L
never gets the chance to leave its critical region, so H loops forever.
• Now let us look at some inter-process communication primitives that block instead of
wasting CPU time when they are not allowed to enter their critical regions.
– Sleep: It is a system call that causes the caller to block, i.e. be suspended until
another process wakes it up.
– Wakeup: It is a system call that causes the process specified by the parameter to
wake up.
• As an example of how these primitives can be used let us consider the producer-
consumer problem (also known as the bounded buffer problem)
Implementing Mutual Exclusion without Busy Waiting …

• Producer-consumer problem
– Two processes share a common fixed-size buffer. One of, the
producers, puts information in the buffer, and the other one,
the consumer, takes it out.
– When the producer wants to put a new item in the buffer, it
checks the buffer, if it is full, it goes to sleep, to be awakened
when the consumer has removed one or more items.
– When the consumer wants to remove an item from the
buffer and sees that the buffer is empty, it goes to sleep until
the producer puts something in the buffer and wakes it up.
– Let us see the producer-consumer problem using c
programming
Implementing Mutual Exclusion without Busy Waiting …
• g Problem:
Readin
Assignme– Race condition can occur because access to count is unconstrained. Consider
nt: Other the following situation. The buffer is empty and the consumer has just read
classical count to see if it is 0. At that instant, the scheduler decides to stop running the
IPC consumer temporarily and start running the producer. The producer enters an
problems item in the buffer, increments count, and notices that it is now 1. Reasoning
– Readers the count was just 0, and thus the consumer must be sleeping, and the
and producer calls wakeup to wake the consumer up. Unfortunately, the consumer
Writers is not yet logically asleep, so the wakeup signal is lost. When the consumer
Problem, next runs, it will test the value of count it previously read, find it to be 0, and
The go to sleep. Sooner or later the producer will fill up the buffer and also go to
Sleeping sleep. Both will sleep forever.
Barber – The problem arises because the wakeup signal is lost. A quick fix is to add to
Problem, the rules by adding wakeup-waiting bit. It is a piggy bank for wakeup signals
The Dining – When a wakeup is sent to a process that is still awake, this bit is set.
Philosoph Later, when the process tries to go to sleep, if the wakeup-waiting bit
ers is on, it will be turned off, but the process will stay awake.
Problem
– The wakeup waiting bit cannot be a general solution, especially for any
random number of processes.
Implementing Mutual Exclusion without Busy Waiting …

A. Semaphores
• Semaphores solve the lost-wakeup problem
• A semaphore is a new integer variable type that counts the number of
wakeups saved for future use. A semaphore could have the value 0,
indicating that no wakeups were saved or some positive value if one or
more wakeups were pending.
• Two operations were proposed to implement semaphores: up and down
• DOWN operation
– It checks the value of the semaphore to see if the value is greater than 0. If so it
decrements the value and just continues. If the value is 0, the process is put to
sleep without completing the DOWN operation for the moment
– Checking the value, changing it and going to sleep is all done as a single,
indivisible atomic operation. Once a semaphore operation has started, no other
process can access the semaphore until the operation has completed or
blocked
Implementing Mutual Exclusion without Busy Waiting …

• UP operation
– It increments the value of the semaphore. If one or more processes were sleeping
on that semaphore, unable to complete an earlier DOWN operation, one of them
is chosen by the system and is allowed to complete its DOWN operation
– The process of incrementing the semaphore and waking up one process is also
indivisible.
• Semantics of DOWN and UP operations
void DOWN(s:semaphore)
{
if(s==0) sleep();
s=s-1;
}
void UP(s:semaphore)
{
s=s+1;
wakeup a sleeping process if any;
}
Implementing Mutual Exclusion without Busy Waiting …

– Semaphores can be implemented in either of the two ways:


• As system calls, with the operating system disabling all interrupts
while it is testing the semaphore, updating it, and putting the
process to sleep, if necessary
• If multiple CPUs are being used, each semaphore should be
protected by a lock variable, with the TSL instruction used to make
sure that only one CPU at a time examines the semaphore
– Solving the Producer – Consumer problem using semaphores
Implementing Mutual Exclusion without Busy Waiting …
Implementing Mutual Exclusion without Busy Waiting …

• The solution uses three semaphores: full, to count the number of full
slots, empty, to count the number of empty slots and mutex, to make
sure the producer and the consumer do not access the buffer at the
same time
• Mutex is used for mutual exclusion, i.e. it is designed to guarantee that
only one process at a time will be reading or writing the buffer and the
associated variables
• Full/empty are used for synchronization, i.e. they are designed to
guarantee that certain event sequences do or do not occur
• The producer stops running when the buffer is full, and the consumer
stops running when it is empty.
• Semaphores that are initialized to 1 and are 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
Implementing Mutual Exclusion without Busy Waiting …

• Problems
– Semaphores are too low-level and error prone. If you are not careful
when using them, errors like race condition, deadlocks and other
forms of unpredictable and irreproducible behavior can occur
– Suppose that the two downs in the producer’s code were
interchanged or reversed in order and suppose also the buffer was full
and mutex is 1
down (&mutex);
down (&empty);
– The producer does a down on mutex and mutex becomes 0 and then
the producer does a down on empty. The producer would block since
the buffer is full. Next time the consumer does a down on mutex and
it blocks since mutex is 0. Therefore both processes would block
forever and hence deadlock would occur.
Implementing Mutual Exclusion without Busy Waiting …

B. Monitors
• A monitor is a higher level of synchronization primitive proposed by Hoare
and Branch Hansen to make writing a correct program easier.
• A monitor is a collection of procedures, variables and data structures that are
all grouped together in a special kind of module or package.
• Rules associated with monitors
– Processes may call the procedures in a monitor whenever they want to, but they
can not directly access the monitor’s internal data structures
– Only one procedure can be active in a monitor at any instant. Monitors are
programming language construct, so the compiler knows that they are special and
can handle calls to a monitor procedures differently from other procedure calls
– It is the compiler that implements mutual exclusion. The person writing the
monitor does not have to be aware of how the compiler arranges for mutual
exclusion. It is sufficient to know that by turning all critical regions into monitor
procedure, no two processes will ever execute their critical regions at the same
time.
Implementing Mutual Exclusion without Busy Waiting …
• Monitors use condition variables, along with two operations on them, WAIT and
SIGNAL to block and wake up a process.
– WAIT
• When a monitor procedure discovers that it can not continue, it does a WAIT
on some condition variable that causes the calling procedure to block.
• It allows another process that had been previously prohibited from entering
the monitor to enter now.
– SIGNAL
• A process can wake up its sleeping partner by doing a SIGNAL on the condition
variable that its partner is waiting on
• A process doing a SIGNAL statement must exit the monitor immediately, i.e.
SIGNAL will be the final statement in a monitor procedure. This avoids having
two active processes in a monitor at the same time.
• If a SIGNAL is done on a condition variable on which several processes are
waiting, only one of them, determined by the system scheduler is revived.
– Condition variables are not counters. They do not accumulate signals for later use,
unlike semaphores. If a condition variable is signaled with no one waiting on it, the
signal is lost.
– The WAIT must always come before the SIGNAL
• An outline of the producer-consumer problem with monitors is shown
below
Implementing Mutual Exclusion without Busy Waiting …

– WAIT and SIGNAL are similar to SLEEP and WAKEUP but with one critical difference.
SLEEP and WAKEUP failed because while one process was trying to go to sleep, the other
one was trying to wake it up. With monitors, this cannot happen. The automatic mutual
exclusion on monitor procedures guarantees that if, say, the procedure inside a monitor
discovers that the buffer is full, it will be able to complete the WAIT operation without
having to worry about the possibility that the scheduler may switch to the consumer just
before the WAIT completes.
– Advantage of monitors
• By making mutual exclusion of critical regions automatic, monitors make parallel programming
much less error prone than with semaphores
– Drawback of monitors
• You need a language that has built-in monitors, but languages that have built-in monitors are
rare. But adding semaphores in C, C++ and other languages is easy.
– Drawback of monitors and semaphores
• They were designed for solving the mutual exclusion problem on one or more CPUs that all
have access to a common memory
• In a distributed system consisting of multiple CPUs, each with its own private memory,
connected by a local area network, these primitives become inapplicable
• Semaphores are too low level and monitors are not usable except in a few programming
languages. And none of them provide information exchange between machines
Implementing Mutual Exclusion without Busy Waiting …

C. Message Passing
– This technique uses two primitives: SEND and RECEIVE
– SEND and RECEIVE are system calls and they can be put as
library procedures: SEND(dest, &msg), RECEIVE(source, &msg)
– If no message is available, the receiver could block until one
arrives or could return with an error code
– The producer-consumer problem with message passing
• An outline for the solution of producer-consumer problem with
message passing is shown below
Implementing Mutual Exclusion without Busy Waiting …

• All messages are of the same size


• Messages sent are buffered automatically by the operating system
• The consumer starts out by sending N empty messages
• Whenever the producer has an item to give to the consumer, it takes an
empty message and sends back a full one
• If the producer works faster
– All messages will end up full, waiting for the consumer
– The producer will be blocked, waiting for an empty messages to
comeback
• If the consumer works faster
– All the messages will be empties waiting for the producer to fill
them up
– The consumer will be blocked, waiting for a full message
Implementing Mutual Exclusion without Busy Waiting …

– Message passing variants (How messages are addressed?)


• Using process address
– Assigning each process a unique address and have messages be addressed to
processes
• Using mailbox
– A mailbox is a place to buffer certain number of messages, typically specified
when the mailbox is created
– The address parameters in SEND and RECEIVE calls are mailboxes not
processes
– The producer sends messages containing data to the consumer’s mailbox and
the consumer sends empty messages to the producer’s mailbox
• Rendezvous (Eliminate buffering)
– SEND is done before RECEIVE
– The sending process is blocked until the receive happens at which time the
message can be copied directly from the sender to the receiver, with no
intermediate buffering
– If the receive is done first, the receiver is blocked until a send happens
– It is easier to implement
– It is less flexible since the sender and receiver are forced to run in lock stop
Implementing Mutual Exclusion without Busy Waiting …

– Design issues for message passing


• Messages can be lost. The solution for this problem is using
acknowledgement message
• Acknowledgement message can be lost. The solution for this
problem is to put consecutive sequence numbers in each original
message
• Ambiguous process names. The solution for this problem to use
naming conventions
• Authentication
• Performance, especially if sender and receiver processes are on
the same machine

You might also like