Mutual Exclusion
Slides adapted from “The Art of Multiprocessor Programming”
by Maurice Herlihy & Nir Shavit Slightly
CS4532 Concurrent Programming
Dilum Bandara
Dilum.Bandara@uom.lk
Mutual Exclusion
 Formal problem definitions
 Solutions for 2 threads
 Solutions for n threads
 Fair solutions
 Inherent costs
2
Warning
 You will never use these protocols
 You are advised to understand them
 Same issues show up everywhere
 Except hidden & more complex
3
Thread Events
 Examples
 Assign to shared variable
 Assign to local variable
 Invoke method
 Return from method
 An event a0 of thread A is
 Instantaneous
 No simultaneous events (break ties)
4
time
a0
Threads
 Thread A is (formally) a sequence of events
 a0, a1, ...
 “Trace” model
 Notation: a0  a1 indicates order
5
time
a0 a1 a2 …
Threads are State Machines
6
Events are
transitions
a0
a1
a2
a3
Concurrency
 Thread A
 Thread B
7
time
time
Interleavings
 Events of 2 or more threads
 Interleaved
 Not necessarily independent (why?)
8
time
Intervals
 An interval A0 =(a0, a1) is
 Time between events a0 & a1
9
time
a0 a1
A0
Intervals May Overlap
10
time
a0 a1
A0
b0 b1
B0
Intervals May Be Disjoint
11
time
a0 a1
A0
b0 b1
B0
Precedence
 Interval A0 precedes interval B0
 Notation: A0  B0
 Formally,
 End event of A0 before start event of B0
 Also called “happens before” or “precedes”
12
time
a0 a1
A0
b0 b1
B0
Precedence Ordering
 Never true that A  A
 If A B then not true that B A
 If A B & B C then A C
13
Repeated Events
while (mumble) {
a0; a1;
}
14
a0
k
k-th occurrence
of event a0
A0
k
k-th occurrence of
interval A0 =(a0, a1)
Implementing a Counter
15
public class Counter {
private long value;
public long getAndIncrement() {
temp = value;
value = temp + 1;
return temp;
}
}
Make these steps
indivisible using locks
Locks (Mutual Exclusion)
16
public interface Lock {
public void lock();
public void unlock();
}
release lock
acquire lock
Using Locks
17
Lock x;
....
x.lock()
//critical section
x.unlock()
...
Using Locks (Cont.)
18
public class Counter {
private long value;
private Lock lock;
public long getAndIncrement() {
lock.lock();
try {
int temp = value;
value = value + 1;
} finally {
lock.unlock();
}
return temp;
}}
Release lock
(no matter what)
acquire Lock
Critical section
Locks in Java
 Look at java.util.concurrent.locks.*
 Lock
 ReentrantLock
 acquire() = lock()
 release() = unlock()
19
Mutual Exclusion
 Let CSi
k be thread i’s k-th critical section
execution
 And CSj
m be thread j’s m-th critical section
execution
 Then either
 or
20
CSi
k  CSj
m
CSj
m  CSi
k
Deadlock-Free
 If some thread attempts to acquire the lock, then
some thread will succeed in acquiring the lock
 If some thread calls lock()
 And never acquires the lock
 Then other threads must complete lock() & unlock()
calls infinitely often
 System as a whole makes progress
 Even if individuals starve
21
Starvation-Free
 If some thread calls lock()
 It will eventually return
 Individual threads make progress
22
2-Thread vs. n -Thread Solutions
 2-thread solutions first
 Illustrate most basic ideas
 Fits on one slide
 Then n-Thread solutions
23
2-Thread Conventions
24
class … implements Lock {
…
// thread-local index, 0 or 1
public void lock() {
int i = ThreadID.get();
int j = 1 - i;
…
}
}
Henceforth: i is current
thread, j is other thread
LockOne
25
class LockOne implements Lock {
private volatile boolean[] flag =
new boolean[2];
public void lock() {
flag[i] = true;
while (flag[j]) {}
}
public void unlock() {
flag[i] = false;
}
LockOne (Cont.)
26
class LockOne implements Lock {
private volatile boolean[] flag =
new boolean[2];
public void lock() {
flag[i] = true;
while (flag[j]) {}
}
Wait for other
flag to go false
Set my flag
LockOne Satisfies Mutual Exclusion
 Suppose it doesn’t satisfy Mutual exclusion
 So assume CSA
j overlaps CSB
k
 Consider each thread's last (j-th & k-th) read &
write in the lock() method before entering
 Derive a contradiction
27
Deadlock Freedom
 LockOne Fails deadlock-freedom
 Concurrent execution can deadlock
 Sequential executions OK
28
flag[i] = true; flag[j] = true;
while (flag[j]){} while (flag[i]){}
LockTwo
29
public class LockTwo implements Lock {
private volatile int victim;
public void lock() {
victim = i;
while (victim == i) {};
}
public void unlock() {}
}
Let other go
first
Wait for
permission
Nothing to do
LockTwo Claims
 Satisfies mutual exclusion
 If thread i in CS
 Then victim == j
 Can’t be both 0 & 1
 Not deadlock free
 Concurrent execution does not
 Sequential execution deadlocks
 A thread alone can’t get in
30
public void LockTwo() {
victim = i;
while (victim == i) {};
}
Peterson’s Algorithm
31
public void lock() {
flag[i] = true;
victim = i;
while (flag[j] && victim == i) {};
}
public void unlock() {
flag[i] = false;
}
Announce I’m
interested
Defer to other
Wait while other
interested & I’m the
victim
No longer
interested
Mutual Exclusion
32
 If thread 1 in critical
section,
 flag[1]=true,
 victim = 0
public void lock() {
flag[i] = true;
victim = i;
while (flag[j] && victim == i) {};
• If thread 0 in critical
section,
– flag[0]=true,
– victim = 1
Can’t both be true
Deadlock Free
 Thread blocked
 Only at while loop
 Only if it is the victim
 One or the other must not be the victim
33
public void lock() {
…
while (flag[j] && victim == i) {};
Starvation Free
 Thread i blocked
only if j repeatedly
re-enters so that
flag[j] == true &
victim == i
 When j re-enters
 it sets victim to j
 So i gets in
34
public void lock() {
flag[i] = true;
victim = i;
while (flag[j] && victim == i) {};
}
public void unlock() {
flag[i] = false;
}
Exercise
 Will combination of 2 locks be deadlock free?
Lock L1, L2
Thread 1 Thread 2
L1.lock() L1.lock()
L2.lock() L2.lock()
Thread 1 Thread 2
L1.lock() L2.lock()
L2.lock() L1.lock()
35
Filter Algorithm for n Threads
 There are n – 1 “waiting rooms” called levels
 At each level
 At least 1 enters level l
 At least 1 blocked, if many try to enter level l
 Only 1 thread makes it through
36
ncs
cs
Filter
37
class Filter implements Lock {
volatile int[] level; // level[i] for thread i
volatile int[] victim; // victim[L] for level L
public Filter(int n) {
level = new int[n];
victim = new int[n];
for (int i = 1; i < n; i++) {
level[i] = 0;
}}
…
}
level
victim
n-1
n-1
0
1
0 0 0 0 0 0
4
2
2
Thread 2 at level 4
0
4
Filter (Cont.)
38
class Filter implements Lock {
…
public void lock(){
for (int L = 1; L < n; L++) {
level[i] = L;
victim[L] = i;
while (($ k != i) (level[k] >= L &&
victim[L] == i ));
}}
public void unlock() {
level[i] = 0;
}}
One level at a time
Announce intention to
enter level L
Give priority to anyone
but me
Filter (Cont.)
39
class Filter implements Lock {
int level[n];
int victim[n];
public void lock() {
for (int L = 1; L < n; L++) {
level[i] = L;
victim[L] = i;
while (($ k != i) level[k] >= L) &&
victim[L] == i);
}}
public void release(int i) {
level[i] = 0;
}} Wait as long as someone else is at same or higher
level, and I’m designated victim
Filter (Cont.)
40
class Filter implements Lock {
int level[n];
int victim[n];
public void lock() {
for (int L = 1; L < n; L++) {
level[i] = L;
victim[L] = i;
while (($ k != i) level[k] >= L) &&
victim[L] == i);
}}
public void release(int i) {
level[i] = 0;
}}
Thread enters level L when it completes loop
Claim
 Start at level L = 0
 At most n - L threads enter level L
 Mutual exclusion at level L = n – 1
41
ncs
cs L=n-1
L=1
L=n-2
L=0
No Starvation
 Filter Lock satisfies properties
 Just like Peterson Algorithm at any level
 So no one starves
 But what about fairness?
 Threads can be overtaken by others
42
Bounded Waiting Concept
 Starvation-freedom guarantees every thread that
calls lock() eventually enters critical section
 But no guarantees about how long it’ll take
 Want stronger fairness guarantees
 Ideally of A calls lock() before B, A should enter the
critical section before B
 Thread not “overtaken” too much
43
Bounded Waiting (Cont.)
 Divide lock() method into 2 parts
 Doorway section
 Written DA
 Always finishes in finite steps
 Waiting section
 Written WA
 May take unbounded steps
44
r-Bounded Waiting
 For threads A & B
 If DA
k  DB
j
 A’s k-th doorway precedes B’s j-th doorway
 Then CSA
k  CSB
j+r
 A’s k-th critical section precedes B’s (j + r)-th critical section
 B can’t overtake A by more than r times
 First-come-first-served means r = 0
 A lock is first-come-first-served if, whenever, thread A
finishes its doorway before thread B starts its doorway,
then A cannot be overtaken by B.
45
Fairness Again
 Filter Lock satisfies properties
 No one starves
 But very weak fairness
 Not r-bounded for any r
46
Bakery Algorithm
 Provides First-Come-First-Served
 How?
 Take a “number”
 Wait until lower numbers have been served
 Lexicographic order
 (a, i) < (b, j)
 If a < b, or a = b and i < j
47
Bakery Algorithm
48
class Bakery implements Lock {
volatile boolean[] flag;
volatile Label[] label;
public Bakery (int n) {
flag = new boolean[n];
label = new Label[n];
for (int i = 0; i < n; i++) {
flag[i] = false; label[i] = 0;
}
}
…
n-1
0
f f f f t f
t
2
f
0 0 0 0 5 0
4 0
6
CS
Bakery Algorithm (Cont.)
49
class Bakery implements Lock {
…
public void lock() {
flag[i] = true;
label[i] = max(label[0], …,label[n-1])+1;
while ($k flag[k] &&
(label[i],i) > (label[k],k);
}
Doorway
1. I’m interested
2. Take increasing label (read labels in some arbitrary
order)
Will solution fails if max( ) is not atomic?
Bakery Algorithm
50
class Bakery implements Lock {
boolean flag[n];
int label[n];
public void lock() {
flag[i] = true;
label[i] = max(label[0], …,label[n-1])+1;
while ($k flag[k]
&& (label[i],i) > (label[k],k));
}
Someone is
interested
With lower (label, i) in
lexicographic order
Bakery Algorithm
51
class Bakery implements Lock {
…
public void unlock() {
flag[i] = false;
}
}
No longer interested
labels are always increasing
Properties
 No deadlocks
 There is always one thread with earliest label
 Ties are impossible (why?)
 First-Come-First-Served
 If DA  DB then A’s label is smaller
 Mutual Exclusion
 Labels are strictly non-dicreasing
52
Theorems
 Deadlock-free mutual exclusion for 2 threads
requires at least 2 MRMW registers
 Deadlock-free mutual exclusion for 3 threads
requires at least 3 MRMW registers
 At least n MRMW registers are needed to solve
deadlock-free mutual exclusion
 n registers like Flag[]…
 These solutions are not scalable!!!
53
MRMW – multi-reader multi-writer
Art of Multiprocessor
Programming
54
This work is licensed under a Creative Commons Attribution-ShareAlike
2.5 License.
• You are free:
– to Share — to copy, distribute and transmit the work
– to Remix — to adapt the work
• Under the following conditions:
– Attribution. You must attribute the work to “The Art of Multiprocessor
Programming” (but not in any way that suggests that the authors
endorse you or your use of the work).
– Share Alike. If you alter, transform, or build upon this work, you may
distribute the resulting work only under the same, similar or a
compatible license.
• For any reuse or distribution, you must make clear to others the license
terms of this work. The best way to do this is with a link to
– http://creativecommons.org/licenses/by-sa/3.0/.
• Any of the above conditions can be waived if you get permission from the
copyright holder.
• Nothing in this license impairs or restricts the author's moral rights.

Mutual Exclusion

  • 1.
    Mutual Exclusion Slides adaptedfrom “The Art of Multiprocessor Programming” by Maurice Herlihy & Nir Shavit Slightly CS4532 Concurrent Programming Dilum Bandara Dilum.Bandara@uom.lk
  • 2.
    Mutual Exclusion  Formalproblem definitions  Solutions for 2 threads  Solutions for n threads  Fair solutions  Inherent costs 2
  • 3.
    Warning  You willnever use these protocols  You are advised to understand them  Same issues show up everywhere  Except hidden & more complex 3
  • 4.
    Thread Events  Examples Assign to shared variable  Assign to local variable  Invoke method  Return from method  An event a0 of thread A is  Instantaneous  No simultaneous events (break ties) 4 time a0
  • 5.
    Threads  Thread Ais (formally) a sequence of events  a0, a1, ...  “Trace” model  Notation: a0  a1 indicates order 5 time a0 a1 a2 …
  • 6.
    Threads are StateMachines 6 Events are transitions a0 a1 a2 a3
  • 7.
    Concurrency  Thread A Thread B 7 time time
  • 8.
    Interleavings  Events of2 or more threads  Interleaved  Not necessarily independent (why?) 8 time
  • 9.
    Intervals  An intervalA0 =(a0, a1) is  Time between events a0 & a1 9 time a0 a1 A0
  • 10.
  • 11.
    Intervals May BeDisjoint 11 time a0 a1 A0 b0 b1 B0
  • 12.
    Precedence  Interval A0precedes interval B0  Notation: A0  B0  Formally,  End event of A0 before start event of B0  Also called “happens before” or “precedes” 12 time a0 a1 A0 b0 b1 B0
  • 13.
    Precedence Ordering  Nevertrue that A  A  If A B then not true that B A  If A B & B C then A C 13
  • 14.
    Repeated Events while (mumble){ a0; a1; } 14 a0 k k-th occurrence of event a0 A0 k k-th occurrence of interval A0 =(a0, a1)
  • 15.
    Implementing a Counter 15 publicclass Counter { private long value; public long getAndIncrement() { temp = value; value = temp + 1; return temp; } } Make these steps indivisible using locks
  • 16.
    Locks (Mutual Exclusion) 16 publicinterface Lock { public void lock(); public void unlock(); } release lock acquire lock
  • 17.
  • 18.
    Using Locks (Cont.) 18 publicclass Counter { private long value; private Lock lock; public long getAndIncrement() { lock.lock(); try { int temp = value; value = value + 1; } finally { lock.unlock(); } return temp; }} Release lock (no matter what) acquire Lock Critical section
  • 19.
    Locks in Java Look at java.util.concurrent.locks.*  Lock  ReentrantLock  acquire() = lock()  release() = unlock() 19
  • 20.
    Mutual Exclusion  LetCSi k be thread i’s k-th critical section execution  And CSj m be thread j’s m-th critical section execution  Then either  or 20 CSi k  CSj m CSj m  CSi k
  • 21.
    Deadlock-Free  If somethread attempts to acquire the lock, then some thread will succeed in acquiring the lock  If some thread calls lock()  And never acquires the lock  Then other threads must complete lock() & unlock() calls infinitely often  System as a whole makes progress  Even if individuals starve 21
  • 22.
    Starvation-Free  If somethread calls lock()  It will eventually return  Individual threads make progress 22
  • 23.
    2-Thread vs. n-Thread Solutions  2-thread solutions first  Illustrate most basic ideas  Fits on one slide  Then n-Thread solutions 23
  • 24.
    2-Thread Conventions 24 class …implements Lock { … // thread-local index, 0 or 1 public void lock() { int i = ThreadID.get(); int j = 1 - i; … } } Henceforth: i is current thread, j is other thread
  • 25.
    LockOne 25 class LockOne implementsLock { private volatile boolean[] flag = new boolean[2]; public void lock() { flag[i] = true; while (flag[j]) {} } public void unlock() { flag[i] = false; }
  • 26.
    LockOne (Cont.) 26 class LockOneimplements Lock { private volatile boolean[] flag = new boolean[2]; public void lock() { flag[i] = true; while (flag[j]) {} } Wait for other flag to go false Set my flag
  • 27.
    LockOne Satisfies MutualExclusion  Suppose it doesn’t satisfy Mutual exclusion  So assume CSA j overlaps CSB k  Consider each thread's last (j-th & k-th) read & write in the lock() method before entering  Derive a contradiction 27
  • 28.
    Deadlock Freedom  LockOneFails deadlock-freedom  Concurrent execution can deadlock  Sequential executions OK 28 flag[i] = true; flag[j] = true; while (flag[j]){} while (flag[i]){}
  • 29.
    LockTwo 29 public class LockTwoimplements Lock { private volatile int victim; public void lock() { victim = i; while (victim == i) {}; } public void unlock() {} } Let other go first Wait for permission Nothing to do
  • 30.
    LockTwo Claims  Satisfiesmutual exclusion  If thread i in CS  Then victim == j  Can’t be both 0 & 1  Not deadlock free  Concurrent execution does not  Sequential execution deadlocks  A thread alone can’t get in 30 public void LockTwo() { victim = i; while (victim == i) {}; }
  • 31.
    Peterson’s Algorithm 31 public voidlock() { flag[i] = true; victim = i; while (flag[j] && victim == i) {}; } public void unlock() { flag[i] = false; } Announce I’m interested Defer to other Wait while other interested & I’m the victim No longer interested
  • 32.
    Mutual Exclusion 32  Ifthread 1 in critical section,  flag[1]=true,  victim = 0 public void lock() { flag[i] = true; victim = i; while (flag[j] && victim == i) {}; • If thread 0 in critical section, – flag[0]=true, – victim = 1 Can’t both be true
  • 33.
    Deadlock Free  Threadblocked  Only at while loop  Only if it is the victim  One or the other must not be the victim 33 public void lock() { … while (flag[j] && victim == i) {};
  • 34.
    Starvation Free  Threadi blocked only if j repeatedly re-enters so that flag[j] == true & victim == i  When j re-enters  it sets victim to j  So i gets in 34 public void lock() { flag[i] = true; victim = i; while (flag[j] && victim == i) {}; } public void unlock() { flag[i] = false; }
  • 35.
    Exercise  Will combinationof 2 locks be deadlock free? Lock L1, L2 Thread 1 Thread 2 L1.lock() L1.lock() L2.lock() L2.lock() Thread 1 Thread 2 L1.lock() L2.lock() L2.lock() L1.lock() 35
  • 36.
    Filter Algorithm forn Threads  There are n – 1 “waiting rooms” called levels  At each level  At least 1 enters level l  At least 1 blocked, if many try to enter level l  Only 1 thread makes it through 36 ncs cs
  • 37.
    Filter 37 class Filter implementsLock { volatile int[] level; // level[i] for thread i volatile int[] victim; // victim[L] for level L public Filter(int n) { level = new int[n]; victim = new int[n]; for (int i = 1; i < n; i++) { level[i] = 0; }} … } level victim n-1 n-1 0 1 0 0 0 0 0 0 4 2 2 Thread 2 at level 4 0 4
  • 38.
    Filter (Cont.) 38 class Filterimplements Lock { … public void lock(){ for (int L = 1; L < n; L++) { level[i] = L; victim[L] = i; while (($ k != i) (level[k] >= L && victim[L] == i )); }} public void unlock() { level[i] = 0; }} One level at a time Announce intention to enter level L Give priority to anyone but me
  • 39.
    Filter (Cont.) 39 class Filterimplements Lock { int level[n]; int victim[n]; public void lock() { for (int L = 1; L < n; L++) { level[i] = L; victim[L] = i; while (($ k != i) level[k] >= L) && victim[L] == i); }} public void release(int i) { level[i] = 0; }} Wait as long as someone else is at same or higher level, and I’m designated victim
  • 40.
    Filter (Cont.) 40 class Filterimplements Lock { int level[n]; int victim[n]; public void lock() { for (int L = 1; L < n; L++) { level[i] = L; victim[L] = i; while (($ k != i) level[k] >= L) && victim[L] == i); }} public void release(int i) { level[i] = 0; }} Thread enters level L when it completes loop
  • 41.
    Claim  Start atlevel L = 0  At most n - L threads enter level L  Mutual exclusion at level L = n – 1 41 ncs cs L=n-1 L=1 L=n-2 L=0
  • 42.
    No Starvation  FilterLock satisfies properties  Just like Peterson Algorithm at any level  So no one starves  But what about fairness?  Threads can be overtaken by others 42
  • 43.
    Bounded Waiting Concept Starvation-freedom guarantees every thread that calls lock() eventually enters critical section  But no guarantees about how long it’ll take  Want stronger fairness guarantees  Ideally of A calls lock() before B, A should enter the critical section before B  Thread not “overtaken” too much 43
  • 44.
    Bounded Waiting (Cont.) Divide lock() method into 2 parts  Doorway section  Written DA  Always finishes in finite steps  Waiting section  Written WA  May take unbounded steps 44
  • 45.
    r-Bounded Waiting  Forthreads A & B  If DA k  DB j  A’s k-th doorway precedes B’s j-th doorway  Then CSA k  CSB j+r  A’s k-th critical section precedes B’s (j + r)-th critical section  B can’t overtake A by more than r times  First-come-first-served means r = 0  A lock is first-come-first-served if, whenever, thread A finishes its doorway before thread B starts its doorway, then A cannot be overtaken by B. 45
  • 46.
    Fairness Again  FilterLock satisfies properties  No one starves  But very weak fairness  Not r-bounded for any r 46
  • 47.
    Bakery Algorithm  ProvidesFirst-Come-First-Served  How?  Take a “number”  Wait until lower numbers have been served  Lexicographic order  (a, i) < (b, j)  If a < b, or a = b and i < j 47
  • 48.
    Bakery Algorithm 48 class Bakeryimplements Lock { volatile boolean[] flag; volatile Label[] label; public Bakery (int n) { flag = new boolean[n]; label = new Label[n]; for (int i = 0; i < n; i++) { flag[i] = false; label[i] = 0; } } … n-1 0 f f f f t f t 2 f 0 0 0 0 5 0 4 0 6 CS
  • 49.
    Bakery Algorithm (Cont.) 49 classBakery implements Lock { … public void lock() { flag[i] = true; label[i] = max(label[0], …,label[n-1])+1; while ($k flag[k] && (label[i],i) > (label[k],k); } Doorway 1. I’m interested 2. Take increasing label (read labels in some arbitrary order) Will solution fails if max( ) is not atomic?
  • 50.
    Bakery Algorithm 50 class Bakeryimplements Lock { boolean flag[n]; int label[n]; public void lock() { flag[i] = true; label[i] = max(label[0], …,label[n-1])+1; while ($k flag[k] && (label[i],i) > (label[k],k)); } Someone is interested With lower (label, i) in lexicographic order
  • 51.
    Bakery Algorithm 51 class Bakeryimplements Lock { … public void unlock() { flag[i] = false; } } No longer interested labels are always increasing
  • 52.
    Properties  No deadlocks There is always one thread with earliest label  Ties are impossible (why?)  First-Come-First-Served  If DA  DB then A’s label is smaller  Mutual Exclusion  Labels are strictly non-dicreasing 52
  • 53.
    Theorems  Deadlock-free mutualexclusion for 2 threads requires at least 2 MRMW registers  Deadlock-free mutual exclusion for 3 threads requires at least 3 MRMW registers  At least n MRMW registers are needed to solve deadlock-free mutual exclusion  n registers like Flag[]…  These solutions are not scalable!!! 53 MRMW – multi-reader multi-writer
  • 54.
    Art of Multiprocessor Programming 54 Thiswork is licensed under a Creative Commons Attribution-ShareAlike 2.5 License. • You are free: – to Share — to copy, distribute and transmit the work – to Remix — to adapt the work • Under the following conditions: – Attribution. You must attribute the work to “The Art of Multiprocessor Programming” (but not in any way that suggests that the authors endorse you or your use of the work). – Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license. • For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to – http://creativecommons.org/licenses/by-sa/3.0/. • Any of the above conditions can be waived if you get permission from the copyright holder. • Nothing in this license impairs or restricts the author's moral rights.