Title: Concurrency
1Concurrency
- Operating Systems
- Fall 2002
2Concurrency pros and cons
- Concurrency is good for users
- One of the reasons for multiprogramming
- Working on the same problem, simultaneous
execution of programs, background execution - Concurrency is a pain in the neck for the
system - Access to shared data structures
- Deadlock due to resource contention
- Enabling process interaction
3Mutual Exclusion
- OS is an instance of concurrent programming
- Multiple activities may take place in the same
time - Concurrent execution of operations involving
multiple steps is problematic - Example updating linked list
- Concurrent access to a shared data structure must
be mutually exclusive
4new-gtnextcurrent.next
insert_after(current,new)
current.nextnew
new
current
new
current
5remove_next(current)
tmpcurrent.next current.nextcurrent.next.next
free(tmp)
current
current
6new
current
new
current
new
current
7Atomic operations
- A generic solution is to execute an operation
atomically - All the steps are perceived as executed in a
single point of time - insert_after(current,new) remove_next(current),
or - remove_next(current) insert_after(current,new)
8The Critical Section Model
- A code within a critical section must be executed
exclusively by a single process
do
critical section
remainder section
while(1)
9Linked list example
do
do
tmpcurrent.next current.nextcurrent.next.next
free(tmp)
new-gtnextcurrent.next
current.nextnew
remainder section
remainder section
while(1)
while(1)
10The Critical Section Problem
- n processes P0,,Pn-1
- Processes are communicating through shared
atomic read/write variables - x is a shared variable, l is a local variable
- Read takes the current value
- Write assigns a provided value
11Requirements
- Mutual Exclusion If process Pi is executing its
C.S., then no other process is in its C.S. - Progress If Pi is in its entry section and no
process is in C.S., then some process eventually
enters C.S. - Fairness If no process remains in C.S. forever,
then each process requesting entry to C.S. will
be eventually let into C.S.
12Solving the CS problem (n2)
13Solving the CS problem (n2)
14Solving the CS problem (n2)
15Petersons algorithm for n2
16Bakery algorithm of Lamport
- Critical section algorithm for any ngt1
- Each time a process is requesting an entry to CS,
assign it a ticket which is - Unique and monotonically increasing
- Let the process into CS in the order of their
numbers
17Choosing a ticket
18Bakery algorithm for n processes
19Correctness
Lemma
Mutual exclusion is immediate from this lemma It
is easy to show that Progress and Fairness
hold as well (Exercise 47 in the notes -)
20Hardware primitives
- Elementary building blocks capable of performing
certain steps atomically - Should be universal to allow for solving
versatile synchronization problems - Several such primitives were identified
- Test-and-set
- Fetch-and-add
- Compare-and-swap
21Test-and-Set
- test-and-set(lock)
-
- templock
- lock1
- return temp
-
- Shared int lock, initially 0
- do
- while(test-and-set(lock))
- critical section
- lock0
- reminder section
- while(1)
22Higher level abstractions
- Atomic primitives bring convenience
- Using hardware primitives make programs
non-portable - Higher level software abstractions are
represented by - Semaphores
- Monitors
23Semaphores
- Invented by Edsger Dijkstra in 1968
- Interface consists of two primitives
- P() and V()
24Notes on the Language
- Dutch P Proberen, V Verhogen
- Hebrew P ????, V ????
- English P() wait(), V() signal()
25Semaphores initial value
- Initial value of a semaphore indicates how many
identical instances of the critical resource
exist - A semaphore initialized to 1 is called a mutex
(mutual exclusion) - P(mutex)
- critical section
- V(mutex)
26Programming with semaphores
- Semaphores is a powerful programming abstraction
- Define a semaphore for each critical resource
- E.g., one for each linked list
- Granularity?
- Concurrent processes access appropriate
semaphores when synch. is needed
27Implementing semaphores
- All the CS solutions so far imply busy waiting
- Burning CPU cycles while being blocked
- Semaphore definition does not necessarily imply
busy waiting! - Semaphores can be implemented efficiently by the
system - P() is explicitly telling the system Hey, I
cannot proceed, you can preempt me
28Implementing Semaphores
- Hence, in fact, a semaphore is a record
(structure)
type semaphore record count
integer queue list of
process end var S semaphore
- When a process must wait for a semaphore S, it is
blocked and put on the semaphores queue - The signal operation removes (acc. to a fair
policy like FIFO) one process from the queue and
puts it in the list of ready processes
29Semaphores operations (atomic)
P(S) S.count-- if (S.countlt0)
place this process in S.queue block this
process
V(S) S.count if (S.count lt 0)
remove a process P from S.queue place this
process P on ready list
S.count must be initialized to a nonnegative
value (depending on application)
30The producer/consumer problem
- A producer process produces information that is
consumed by a consumer process - We need a buffer to hold items that are produced
and eventually consumed - A common paradigm for cooperating processes
31P/C unbounded buffer
- We assume first an unbounded buffer consisting
of a linear array of elements - in points to the next item to be produced
- out points to the next item to be consumed
32P/C unbounded buffer (solution)
- We need a semaphore S to perform mutual exclusion
on the buffer only 1 process at a time can
access the buffer - We need another semaphore N to synchronize
producer and consumer on the number N ( in -
out) of items in the buffer - an item can be consumed only after it has been
created
33Solution of P/C unbounded buffer
Initialization S.count1 N.count0
inout0
append(v) binv in
Producer repeat produce v P(S)
append(v) V(S) V(N) forever
Consumer repeat P(N) P(S) wtake()
V(S) consume(w) forever
take() wbout out return w
34P/C finite circular buffer of size k
- can consume only when number N of (consumable)
items is at least 1 (now N!in-out) - can produce only when number E of empty spaces is
at least 1
35P/C finite circular buffer of size k
- As before
- we need a semaphore S to have mutual exclusion on
buffer access - we need a semaphore N to synchronize producer and
consumer on the number of consumable items - In addition
- we need a semaphore E to synchronize producer and
consumer on the number of empty spaces
36Solution of P/C finite circular buffer of size k
Initialization S.count1 in0
N.count0 out0 E.countk
append(v) binv in(in1) mod k
Producer repeat produce v P(E) P(S)
append(v) V(S) V(N) forever
Consumer repeat P(N) P(S) wtake()
V(S) V(E) consume(w) forever
take() wbout out(out1) mod
k return w
critical sections
37Monitors
- Only a single process at a time can be active
within the monitor - gt other processes calling Pi() are queued
- Conditional variables for finer grained
synchronization - x.wait() suspend the execution until another
process calls x.signal()
monitor monitor-name shared variable
declarations procedure P1()
procedure Pn()
38Monitor
- Awaiting processes are either in the entrance
queue or in a condition queue - A process puts itself into condition queue cn by
issuing cwait(cn) - csignal(cn) brings into the monitor 1 process in
condition cn queue - Hence csignal(cn) blocks the calling process and
puts it in the urgent queue (unless csignal is
the last operation of the monitor procedure)
39Producer/Consumer problem
- Two types of processes
- producers
- consumers
- Synchronization is now confined within the
monitor - append(.) and take(.) are procedures within the
monitor are the only means by which P/C can
access the buffer - If these procedures are correct, synchronization
will be correct for all participating processes
ProducerI repeat produce v
Append(v) forever ConsumerI repeat Take(v)
consume v forever
40Monitor for the bounded P/C problem
- Monitor needs to hold the buffer
- buffer array0..k-1 of items
- needs two condition variables
- notfull csignal(notfull) indicates that the
buffer is not full - notemty csignal(notempty) indicates that the
buffer is not empty - needs buffer pointers and counts
- nextin points to next item to be appended
- nextout points to next item to be taken
- count holds the number of items in buffer
41Monitor for the bounded P/C problem
Monitor boundedbuffer buffer array0..k-1 of
items nextin0, nextout0, count0
integer notfull, notempty condition
Append(v) if (countk) cwait(notfull)
buffernextin v nextin nextin1 mod k
count csignal(notempty) Take(v)
if (count0) cwait(notempty) v
buffernextout nextout nextout1 mod k
count-- csignal(notfull)