ready[0]

Process/Thread
Synchronization (Part 2)
Modified from Chapter 6
for 170 with Nachos
threads, Tao Yang, 2012
Operating System Concepts – 8th Edition
Silberschatz, Galvin and Gagne ©2009
What to learn?
 Software and hardware solutions
of the synchronization primitives
 Deadlock/starvation
 More synchronization applications
6.2
Implementation of Synchronization
Primitives
 Software solutions through shared memory data
checking or message passing.
 Assume that the LOAD and STORE instructions
are atomic for shared variables;
that is, cannot be interrupted
 Hardware-assisted solutions
 Properties (e.g. for implementing a lock)


Mutual exclusion: only one gets a lock.
Progress: when multiple threads try to acquire a
lock, one can get it if nobody has it.

Bounded waiting: lock waiting time is limited.
6.3
Software Solution for 2
processes/threads
 Two processes use a shared variable to coordinate

int turn=0; // whose turn for the critical section
 Process 0
while (turn != 0);
critical section
turn= 1; //give turn to P1
 Process 1:
while (turn != 1);
critical section
turn= 0; //give turn to P0
 Mutual exclusion? Progress? Bounded waiting?
6.4
Mutual exclusion?
 Prove by contraction. Assume both Processes 0
and 1 are in the critical section.
 Process 0
while (turn != 0);
turn==0
critical section
turn= 1; //give turn to P1
 Process 1:
while (turn != 1);
turn==1
critical section
turn= 0; //give turn to P0
 (turn==0) and (turn==1) is false
6.5
Progress?
 The two processes use a shared variable to coordinate

int turn=0; // whose turn for the critical section
 Process 0
while (turn != 0);
critical section
turn= 1;
 Process 0 tries again:
Loop forever
while (turn != 0);
critical section
turn= 1;
6.6
Peterson’s Solution
 Two process software solution (Text book chapter
6.3)
 Assume that the LOAD and STORE instructions
are atomic; that is, cannot be interrupted.
 The two processes share two variables:


int turn;
 indicates whose turn it is to enter the critical
section.
Boolean ready[2]
 indicate if a process is ready to enter the
critical section. ready[0] = true implies that
process P0 is ready!
6.7
Peterson’s Algorithm
Process P0:
ready[0] = TRUE;
Ready to enter critical section;
Wait if another process is in.
turn = 1;
while (ready[1] && turn == 1);
Critical section
Exit critical section
ready[0] = FALSE;
Process P1:
ready[1] = TRUE;
turn = 0;
while (ready[0] && turn == 0);
Critical section
ready[1] = FALSE;
6.8
Mutual exclusion?
Progress?
Bounded waiting?
Mutual Execution? Prove by contradition
Process P0:
ready[0] = TRUE;
turn = 1;
while (ready[1] && turn == 1);
critical section
ready[0]=T and (Ready[1]=F or turn=0)
ready[0] = FALSE;
Process P1:
ready[1] = TRUE;
turn = 0;
while (ready[0] && turn == 0);
critical section
ready[1]=T and (Ready[0]=F or turn=1)
ready[1] = FALSE;
Both conditions are true, which is not
possible6.9
Progress? Can both P0/P1 wait forever?
Process P0:
ready[0] = TRUE;
Loop forever
turn = 1;
while (ready[1] && turn == 1);
(Ready[1]=T and turn=1)
critical section
ready[0] = FALSE;
Process P1:
ready[1] = TRUE;
Loop forever
turn = 0;
while (ready[0] && turn == 0);
(Ready[0]=T and turn=0)
critical section
ready[1] = FALSE;
Both conditions are true, which is not
6.10
possible
Progress? Can P0 wait forever after P1 leaves
Process P0:
ready[0] = TRUE;
turn = 1;
while (ready[1] && turn == 1);
Loop forever
(ready[1]=T and turn=1)
critical section
ready[0] = FALSE;
Process P1:
ready[1] = TRUE;
turn = 0;
while (ready[0] && turn == 0);
critical section
ready[1] = FALSE;
ready[1]=F
Both conditions are true, which is not
possible. 6.11
Hardware Solution for Synchronization
 Many systems provide hardware support for critical section
code
 Uniprocessors – could disable interrupts


Currently running code would execute without preemption
 Project 1.
Generally too inefficient on multiprocessor systems
 Operating systems using this not broadly scalable
 Modern machines provide special atomic hardware instructions
 Atomic


= non-interruptable
Either test memory word and set value
Or swap contents of two memory words
6.12
Atomic TestAndSet Instruction
 Definition: Fetch the value of a shared variable
and then set it to TRUE atomically.
boolean TestAndSet (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv:
}
6.13
Lock Solution using TestAndSet
 Shared boolean variable: lock.
“True” means somebody has acquired the lock.
 initialized to FALSE.

 Solution:
while ( TestAndSet (&lock )) ; // wait
Critical section;
lock = FALSE;
Mutual exclusion?
Progress?
Bounded waiting? no
6.14
Mutual exclusion? Assume P0 gets first,
and then P1
Process P0:
Property:
Lock=T  somebody is in the critical section
Lock=F  nobody is in the critical section.
while(TestAndSet (&lock));
critical section
lock = FALSE;
}
C1: lock was F in last TestAndSet().
TestAndSet() returns F
Now lock is T.
Process P1:
while(TestAndSet (&lock));
critical section
lock = FALSE;
C2: lock was F in last TestAndSet().
TestAndSet() returns F
Conditions C1 and then C2: cannot be true
6.15
Bounded Waiting?
Process P0:
Process P1:
TestAndSet (&lock)); //get in
…
TestAndSet(&lock);// wait
Lock=FALSE; //get out
TestAndSet(&lock);// get in
…
TestAndSet(&lock);// wait
Lock=FALSE; //get out
TestAndSet(&lock);// get in
…
TestAndSet(&lock);// wait
Lock=FALSE; //get out
TestAndSet(&lock);// get in
TestAndSet(&lock);// wait
6.16
Atomic Swap Instruction
 Definition: exchange values of two
variables automatically.
void Swap (boolean *a, boolean *b)
{
boolean temp = *a;
*a = *b;
*b = temp:
}
6.17
Lock Solution using Swap
 Shared Boolean variable lock initialized to FALSE; Each
process has a local Boolean variable key
 Solution:
key = TRUE;
while ( key == TRUE)
Swap (&lock, &key );
Critical section
lock = FALSE;
Mutual exclusion, progress.
bounded waiting?
6.18
Key:
True
Lock:
False
TestAndSet Solution with Bounded Waiting
Enter Critical Section if:
Lock =False or Waiting[i]==False
Waiting[]
T
T
T
F
Assign with cyclic order for fairness
6.19
Bounded-waiting Mutual Exclusion
with TestAndSet()
waiting[i] = TRUE;
key = TRUE;
while (waiting[i] && key)
key = TestAndSet(&lock);
Loop if this process
should wait and
Lock =True
waiting[i] = FALSE;
Critical section
j = (i + 1) % n;
while ((j != i) && waiting[j]== False)
j = (j + 1) % n;
if (j == i) lock = FALSE;
else
waiting[j] = FALSE;
6.20
Find a waiting process j
and set waiting[j]=False
Or Set Lock=False
Deadlock and Starvation
 Deadlock – two or more processes (or threads) are waiting
indefinitely for an event that can be only caused by one of these
waiting processes
 Starvation – indefinite blocking. A process is in a waiting queue
forever.
 Let S and Q be two locks:
P0
P1
Acquire(S);
Acquire(Q);
Acquire (Q);
Acquire (S);
.
.
.
.
.
.
Release (Q);
Release(S);
Release (S);
Release(Q);
6.21
Deadlock Avoidance
 Order the locks and always acquire the locks in that order.
 Eliminate circular waiting
P0
P1
Acquire(S);
Acquire(S);
Acquire(Q);
Acquire (Q);
.
.
.
.
.
.
Release(Q);
Release (Q);
Release(S);
Release (S);
6.22
Classical Problems of Synchronization
 Bounded-Buffer Problem
 Laundromat
 Barriers
 Readers and Writers Problem
6.23
Barriers
6.24
Barriers called multiple times
barrier(3);
barrier(3);
6.25
Implement a barrier
int count=0;
barrier(N) { //for N threads
mylock->Acquire();
count ++;
mylock->Release();
What’s wrong with this?
while (count <N)
Cond->Wait(mylock);
if(count==N) {
Cond->Broadcast(mylock);
Count=N for next
count=0;
barrier() called in
}
another thread
mylock->Release()
6.26
26
Readers-Writers Problem
 A data set is shared among a number of concurrent processes.

Readers – only read the data set; they do not perform any
updates

Writers – can both read and write
 Requirement:


allow multiple readers to read at the same time.
Only one writer can access the shared data at the same
time.
 Reader/writer access permission table:
Reader
Writer
OK
NO
No
No
Reader
Writer
6.27
Readers-Writers (First try with 1 lock)
 writer
do {
wrt.Acquire(); // wrt is a lock
//
writing is performed
wrt.Release();
} while (TRUE);
 Reader
Reader
Writer
Reader
?
?
Writer
?
?
do {
wrt.Acquire(); // Use wrt lock
//
reading is performed
wrt.Release();
} while (TRUE);
6.28
2nd try using a lock + readcount
 writer
do {
wrt.Acquire(); // Use wrt lock
//
writing is performed
wrt.Release();
} while (TRUE);
 Reader
do {
readcount++; // add a reader counter.
if(readcount==1) wrt.Acquire();
//
reading is performed
readcount--;
if(readcount==0) wrt.Release();
} while (TRUE);
6.29
You may also use a binary semaphore
 writer
do {
wrt.P(); // Use wrt semaphore with initial value=1
//
writing is performed
wrt.V();
What’s wrong with this?
} while (TRUE);
 Reader
readcount is not protected
do {
readcount++; //initial value=0
if(readcount==1) wrt.P();
//
reading is performed
readcount--;
if(readcount==0) wrt.V();
} while (TRUE);
6.30
Readers-Writers Problem (Text Book)
 Shared Data
 Data
set
 Semaphore
mutex initialized to 1
 Semaphore
wrt initialized to 1
 Integer
readcount initialized to 0
6.31
Readers-Writers Problem (textbook)
 The structure of a writer process
do {
wrt.P() ; //Lock wrt
// writing is performed
wrt.V() ; //Unlock wrt
} while (TRUE);
6.32
Readers-Writers Problem (Cont.)
 The structure of a reader process
do {
mutex.P() ;
readcount ++ ;
if (readcount == 1)
wrt.P() ;
mutex.V()
// reading is performed
mutex.P() ;
readcount - - ;
if (readcount == 0)
wrt.V() ;
mutex.V() ;
} while (TRUE);
6.33