Title: Synchronization
1Synchronization
- CSCI 3753 Operating Systems
- Spring 2005
- Prof. Rick Han
2Announcements
- HW 3 is online, due Friday Feb. 25 at 11 am
- PA 2 is coming, assigned next Tuesday
- Midterm is tentatively Thursday March 10
- Read chapter 8
3From last time...
- Many cases where processes and threads want to
access shared common variables, buffers, etc. - Producer-Consumer with a shared bounded buffer in
between - Producer increments counter
- Consumer decrements counter--
- race conditions between producer and consumer
- Machine-level instructions can be interleaved,
resulting in unpredictable value of shared
counter variable
4Synchronization
Bounded Buffer
counter
Producer Process
Consumer Process
buffer0
Data
bufferMAX
while(1) while(counter0) getdata
bufferout out (out1) MAX
counter--
- while(1)
- while(counterMAX)
- bufferin nextdata
- in (in1) MAX
- counter
Producer writes new data into buffer and
increments counter
Consumer reads new data from buffer and
decrements counter
5Synchronization
- counter can translate into several machine
language instructions, e.g. - reg1 counter
- reg1 reg1 1
- counter reg1
counter-- can translate into several machine
language instructions, e.g. reg2 counter
reg2 reg2 - 1 counter reg2
If these low-level instructions are interleaved,
e.g. the Producer process is context-switched
out, and the Consumer process is context-switched
in, and vice versa, then the results of counters
value can be unpredictable
6Synchronization
- Suppose we have the following sequence of
interleaving, where the brackets value denote
the local value of counter in either the producer
or consumers process. Let counter5 initially.
// counter-- reg2 counter reg2
reg2 - 1 counter reg2
- // counter
- reg1 counter
- reg1 reg1 1
- counter reg1
(1) 5
(2) 5
(3) 6
(4) 4
(5) 6
(6) 4
- At the end, counter 4. But if steps (5) and
(6) were reversed, then counter6 !!! - Value of shared variable counter changes
depending upon (an arbitrary) order of writes -
very undesirable!
7Critical Section
- Kernel data structures - e.g. access to list of
open files subject to race condition - Kernel developer must ensure that no such race
conditions occur - Identify critical sections in code where each
process access shared variables - do
- entry section
- critical section (manipulate common
vars) - exit section
- remainder code
- while (1)
- mutual exclusion, bounded waiting, progress
8Critical Section
- How do we protect access to critical sections?
- want to prevent another process from executing
while current process is modifying this variable
- mutual exclusion - disable interrupts
- bad, because I/O may be prevented
- bad, because program may have an infinite loop
9Critical Section
- Dont disable interrupts for the entire time
youre in the critical section - Solution Set a variable/flag called a lock to
indicate that the critical section is busy, then
unset the flag when critical section is done - doesnt disable interrupts in the critical
section - also Petersons solution
10Using a Lock Variable
shared boolean lock FALSE shared int
counter Code for p1 Code for p2 / Acquire
the lock / / Acquire the lock / while(lock)
while(lock) lock TRUE lock
TRUE / Execute critical sect / / Execute
critical sect / counter
counter-- / Release lock / / Release lock
/ lock FALSE lock FALSE
11Busy Wait Condition
shared boolean lock FALSE shared int
counter Code for p1 Code for p2 / Acquire
the lock / / Acquire the lock / while(lock)
while(lock) lock TRUE lock
TRUE / Execute critical sect / / Execute
critical sect / counter
counter-- / Release lock / / Release lock
/ lock FALSE lock FALSE
12Unsafe Solution
shared boolean lock FALSE shared double
balance Code for p1 Code for p2 / Acquire
the lock / / Acquire the lock / while(lock)
while(lock) lock TRUE lock
TRUE / Execute critical sect / / Execute
critical sect / counter
counter-- / Release lock / / Release lock
/ lock FALSE lock FALSE
13Critical Section
- while (lockTRUE)
- lock TRUE
- test-and-set solution doesnt work if process is
interrupted right after while() - Want an atomic instruction testandset() that
tests shared variable lock then sets it - Some hardware provides such an instruction
14Atomic Lock Manipulation
shared boolean lock FALSE shared int
counter Code for p1 Code for p2 / Acquire
the lock / / Acquire the lock /
while(TestandSet(lock)) while(TestandSet(loc
k)) / Execute critical sect / / Execute
critical sect / counter
counter-- / Release lock / / Release lock
/ lock FALSE lock FALSE _____________
_________________________________________________
boolean TestandSet(boolean target) // this
is atomic, one machine instruction boolean rv
target target TRUE return rv
15Atomic Lock Manipulation
- The system is exclusively occupied for only a
short time - the time to test and set the lock,
and not for entire critical section - about 10 instructions
- dont have to disable and reenable interrupts -
time-consuming - disadvantage requires user to put in while()
- low level assembly language manipulation of a
machine instruction TS
16(No Transcript)
17Bounded Buffer Problem
Empty Pool
Producer
Consumer
Full Pool
18Bounded Buffer Problem (2)
producer() buf_type next, here
while(TRUE) produce_item(next) / Claim
an empty / P(empty) P(mutex)
here obtain(empty) V(mutex)
copy_buffer(next, here) P(mutex)
release(here, fullPool) V(mutex) /
Signal a full buffer / V(full)
semaphore mutex 1 semaphore full 0
/ A general (counting) semaphore / semaphore
empty N / A general (counting) semaphore
/ buf_type bufferN fork(producer,
0) fork(consumer, 0)
consumer() buf_type next, here
while(TRUE) / Claim full buffer /
P(mutex) P(full) here
obtain(full) V(mutex) copy_buffer(here,
next) P(mutex) release(here,
emptyPool) V(mutex) / Signal an empty
buffer / V(empty) consume_item(next)
19Bounded Buffer Problem (3)
producer() buf_type next, here
while(TRUE) produce_item(next) / Claim
an empty / P(empty) P(mutex)
here obtain(empty) V(mutex)
copy_buffer(next, here) P(mutex)
release(here, fullPool) V(mutex) /
Signal a full buffer / V(full)
semaphore mutex 1 semaphore full 0
/ A general (counting) semaphore / semaphore
empty N / A general (counting) semaphore
/ buf_type bufferN fork(producer,
0) fork(consumer, 0)
consumer() buf_type next, here
while(TRUE) / Claim full buffer /
P(full) P(mutex) here
obtain(full) V(mutex) copy_buffer(here,
next) P(mutex) release(here,
emptyPool) V(mutex) / Signal an empty
buffer / V(empty) consume_item(next)
20Readers-Writers Problem
Writers
Readers
21Readers-Writers Problem (2)
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Reader
Shared Resource
22Readers-Writers Problem (3)
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Shared Resource
23Readers-Writers Problem (4)
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Writer
Reader
Reader
Writer
Shared Resource
24First Solution
reader() while(TRUE) ltother
computinggt P(mutex) readCount
if(readCount 1) P(writeBlock)
V(mutex) / Critical section /
access(resource) P(mutex)
readCount-- if(readCount 0)
V(writeBlock) V(mutex) resourceType
resource int readCount 0 semaphore mutex
1 semaphore writeBlock 1 fork(reader,
0) fork(writer, 0)
writer() while(TRUE) ltother
computinggt P(writeBlock) / Critical
section / access(resource)
V(writeBlock)
25First Solution (2)
reader() while(TRUE) ltother
computinggt P(mutex) readCount
if(readCount 1) P(writeBlock)
V(mutex) / Critical section /
access(resource) P(mutex)
readCount-- if(readCount 0)
V(writeBlock) V(mutex) resourceType
resource int readCount 0 semaphore mutex
1 semaphore writeBlock 1 fork(reader,
0) fork(writer, 0)
writer() while(TRUE) ltother
computinggt P(writeBlock) / Critical
section / access(resource)
V(writeBlock)
- First reader competes with writers
- Last reader signals writers
- Any writer must wait for all readers
- Readers can starve writers
- Updates can be delayed forever
- May not be what we want
26Writer Precedence
reader() while(TRUE) ltother
computinggt P(readBlock)
P(mutex1) readCount
if(readCount 1) P(writeBlock)
V(mutex1) V(readBlock)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
27Writer Precedence (2)
reader() while(TRUE) ltother
computinggt P(writePending)
P(readBlock) P(mutex1)
readCount if(readCount 1)
P(writeBlock) V(mutex1)
V(readBlock) V(writePending)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
28The Sleepy Barber
- Barber can cut one persons hair at a time
- Other customers wait in a waiting room
Entrance to Waiting Room (sliding door)
Shop Exit
Entrance to Barbers Room (sliding door)
Waiting Room
29Sleepy Barber (aka Bounded Buffer)
customer() while(TRUE) customer
nextCustomer() if(emptyChairs 0)
continue P(chair) P(mutex)
emptyChairs-- takeChair(customer)
V(mutex) V(waitingCustomer)
semaphore mutex 1, chair N,
waitingCustomer 0 int emptyChairs
N fork(customer, 0) fork(barber, 0)
barber() while(TRUE) P(waitingCustomer)
P(mutex) emptyChairs
takeCustomer() V(mutex) V(chair)
30Cigarette Smokers Problem
- Three smokers (processes)
- Each wish to use tobacco, papers, matches
- Only need the three resources periodically
- Must have all at once
- 3 processes sharing 3 resources
- Solvable, but difficult
31Implementing Semaphores
- Minimize effect on the I/O system
- Processes are only blocked on their own critical
sections (not critical sections that they should
not care about) - If disabling interrupts, be sure to bound the
time they are disabled
32Implementing Semaphoresenter() exit()
class semaphore int value public
semaphore(int v 1) value v P()
disableInterrupts() while(value 0)
enableInterrupts() disableInterrupts()
value-- enableInterrupts()
V() disableInterrupts() value
enableInterrupts()
33Implementing SemaphoresTest and Set Instruction
- TS(m) Reg_i memorym memorym TRUE
Data Register
CC Register
R3
m
FALSE
Primary Memory
34Using the TS Instruction
boolean s FALSE . . . while(TS(s))
ltcritical sectiongt s FALSE . . .
semaphore s 1 . . . P(s) ltcritical
sectiongt V(s) . . .
35Implementing the General Semaphore
struct semaphore int value ltinitial
valuegt boolean mutex FALSE boolean hold
TRUE shared struct semaphore s P(struct
semaphore s) while(TS(s.mutex))
s.value-- if(s.value lt 0) ( s.mutex
FALSE while(TS(s.hold)) else
s.mutex FALSE
V(struct semaphore s) while(TS(s.mutex))
s.value if(s.value lt 0) (
while(!s.hold) s.hold FALSE
s.mutex FALSE
36Active vs Passive Semaphores
- A process can dominate the semaphore
- Performs V operation, but continues to execute
- Performs another P operation before releasing the
CPU - Called a passive implementation of V
- Active implementation calls scheduler as part of
the V operation. - Changes semantics of semaphore!
- Cause people to rethink solutions
37Atomic Lock Manipulation
- shared double balance
- shared int lock FALSE
- P1
- enter(lock)
- counter
- exit(lock)
P2 enter(lock) // atomic system
call counter-- exit(lock)
38Atomic Lock Manipulation
enter(lock) exit(lock)
disableInterrupts() disableInterrupts() /
Loop until lock is TRUE / lock FALSE
while(lock) enableInterrupts() / Let
interrupts occur / enableInterrupts()
disableInterrupts() lock TRUE
enableInterrupts()
- Bound the amount of time that interrupts are
disabled - Can include other code to check that it is OK to
assign a lock - but this is still overkill
39(No Transcript)
40Critical Section
- do
- flagi TRUE
- turn j
- while (flagj turnj)
- critical section
- flagi FALSE
- remainder section
- while (TRUE)
41Critical Section
- Solution instead disable only on entry and exit.
Use a shared variable to control access to
another shared variable. - this introduces complexity - what if youre
interrupted while having the lock?