Reminder: Project Ideas are
due by 11:59pm tonight!
Plan for Today
Recap: Dijkstra’s Mutual Exclusion Problem
Why Obvious Solutions Fail
Practical Solutions with Modern Processors
Dijkstra’s Solution
Lamport’s Solution
1
Reminder: Project Ideas are
due by 11:59pm tonight!
2
3
Final Keynote (Sunday):
Steve Huffman
4
5
Decoy Project!
6
Lessons for your Project Submissions:
1. Don’t submit something I will think is a
decoy project! (Too late for that here)
2. Don’t do something that involves breaking
into my house.
3. Do do something creative and unexpected.
7
T2 T3 T4T1
N independent threads
Shared Memory (atomic read and write)
T5 Program:
loop {
non-critical {
…
}
critical {
…
}
}
Requirements:
1. Only one thread may be in the critical section at any time.
2. Each must eventually be able to enter its critical section.
3. Must be symmetrical (all run same program).
4. Cannot make any assumptions about speed of threads.
Clever “Cheating” Solution
8
loop {
if turn == i:
critical_section;
turn = i + 1;
}
T2 T3T1
Shared Memory
turn:
Initially, turn = 1
9
loop {
if turn == i:
critical_section;
turn = i + 1;
}
Initially, turn = 1
Attempted Solution
10
loop {
if not lock:
lock = true;
critical_section;
lock = false;
}
T2 T3T1
Shared Memory
lock:
Attempted Fix
11
loop {
if lock == 0:
lock = i;
if lock == i:
critical_section;
lock = 0;
}
T2 T3T1
Shared Memory
lock:
Attempted Fix of Fix
12
loop {
if lock1 == 0:
lock1 = i;
if lock1 == i:
if lock2 == 0:
lock2 = i;
if lock2 == i:
critical_section;
lock2 = 0;
lock1 = 0;
}
T2 T3T1
Shared Memory
lock1: lock2:
Attempted Fix of Fix of Fix …
13
loop {
if lock1 == 0:
lock1 = i;
if lock1 == i:
if lock2 == 0:
lock2 = i;
if lock2 == i:
critical_section;
lock2 = 0;
lock1 = 0;
}
T2 T3T1
Shared Memory
lock1: lock2:
Do we need to see why 3-locks still breaks?
Uniprocessor
Easy (Kernel Cheating) Solution
14
loop {
non-critical;
disable interrupts
critical_section;
enable interrupts
}
T2 T3T1
Shared Memory
15
ironkernel: arch/arm/cpu/interrupt.rs
16
ironkernel: arch/arm/cpu/interrupt.rs
CPSR: Current Program Status Register
Uniprocessor
Easy (Kernel Cheating) Solution
17
loop {
non-critical;
disable interrupts
critical_section;
enable interrupts
}
T2 T3T1
Shared Memory
How well does this solution work for modern kernels?
Easy (Cheating) Solution
18
T2 T3T1
Shared Memory
(with atomic
read/write/test&set)
lock:
test_and_set(v)
returns current value of v
sets value of v to true
Easy (Cheating) Solution
19
loop {
if not test_and_set(lock):
critical_section;
lock = false;
}
T2 T3T1
Shared Memory
(with atomic
read/write/test&set)
lock:
test_and_set(v)
returns current value of v
sets value of v to true
Does your processor provide such
an instruction?
20
21
Intel x86
22
ARMv7
23
Implementing a Mutex Lock
24
lock_mutex(lock);
critical
unlock_mutex(lock);
LDREX <dest> <location>
<dest> = <location>
Sets monitor on <location> in Exclusive state
STREX <success> <value> <location>
Conditionally store <value> into exclusive <location>.
If permitted, <success> = 1 and <location> = <value>.
If not, <success> = 0 and <location> value unchanged.
Context switch clears monitor (Open) state.
25
lock_mutex(lock);
critical
unlock_mutex(lock);
lock_mutex(lock):
try_again:
LDREX R2, [lock]
if R2 goto try_again
STREX R2, 1, [lock]
if not R2 goto try_again
unlock_mutex(lock):
STR [lock], 0
LDREX <dest> <location>
<dest> = <location>
Sets monitor on <location> in Exclusive state
STREX <success> <value> <location>
Conditionally store <value> into exclusive <location>.
If permitted, <success> = 1 and <location> = <value>.
If not, <success> = 0 and <location> value unchanged.
26
lock_mutex(lock);
critical
unlock_mutex(lock);
lock_mutex(lock):
try_again:
LDREX R2, [lock]
if R2 goto try_again
STREX R2, 1, [lock]
if not R2 goto try_again
unlock_mutex(lock):
STR [lock], 0
What if you care about energy?
27
28
WFE and WFI do not provide synchronization!
Just hints to the processor to save energy.
29
ARMv7
Why two instructions like this instead of one?
30
T2 T3 T4T1
Shared Memory (atomic read and write)
T5
Program:
loop {
non-critical {
…
}
critical {
…
}
}
Requirements:
1. Only one thread may be in the critical section at any time.
2. Each must eventually be able to enter its critical section.
3. Must be symmetrical (all run same program).
4. Cannot make any assumptions about speed of threads.
no special combined atomic operations (e.g., test-and-set, LDREX/STREX)
31
Dijkstra (1973)
From Edgar Daylight’s collection:
http://www.dijkstrascry.com/node/59
1965
32
33
Program for Processor i
loop {
b[i] := false
L1: if k != i
c[i] := true
if b[k]
k := i
goto L1
else:
c[i] := false
for j in [1, …, N]:
if j != i and not c[j]:
goto L1
critical section;
c[i] := true
b[i] := true
}
Initialization
b[1:N] = [true, true, …]
c[1:N] = [true, true, …]
k = choose([1..N])
34
Safety: only one program can be
in critical section
Program for Processor i
loop {
b[i] := false
L1: if k != i
c[i] := true
if b[k]:
k := i
goto L1
else:
c[i] := false
for j in [1, …, N]:
if j != i and not c[j]:
goto L1
critical section;
c[i] := true
b[i] := true
}
35
Program for Processor i
loop {
b[i] := false
L1: if k != i
c[i] := true
if b[k]:
k := i
goto L1
else:
c[i] := false;
L4: for j in [1, …, N]:
if j != i and not c[j]:
goto L1
critical section;
c[i] := true
b[i] := true
}
How do we know none of the c[.]’s
changed during the loop?
Charge
Think about Dijkstra’s Solution:
How does it guarantee mutual exclusion?
How does it guarantee liveness?
Submit Project Idea by 11:59pm Tonight
36

Mutual Exclusion

  • 1.
    Reminder: Project Ideasare due by 11:59pm tonight!
  • 2.
    Plan for Today Recap:Dijkstra’s Mutual Exclusion Problem Why Obvious Solutions Fail Practical Solutions with Modern Processors Dijkstra’s Solution Lamport’s Solution 1 Reminder: Project Ideas are due by 11:59pm tonight!
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
    6 Lessons for yourProject Submissions: 1. Don’t submit something I will think is a decoy project! (Too late for that here) 2. Don’t do something that involves breaking into my house. 3. Do do something creative and unexpected.
  • 8.
    7 T2 T3 T4T1 Nindependent threads Shared Memory (atomic read and write) T5 Program: loop { non-critical { … } critical { … } } Requirements: 1. Only one thread may be in the critical section at any time. 2. Each must eventually be able to enter its critical section. 3. Must be symmetrical (all run same program). 4. Cannot make any assumptions about speed of threads.
  • 9.
    Clever “Cheating” Solution 8 loop{ if turn == i: critical_section; turn = i + 1; } T2 T3T1 Shared Memory turn: Initially, turn = 1
  • 10.
    9 loop { if turn== i: critical_section; turn = i + 1; } Initially, turn = 1
  • 11.
    Attempted Solution 10 loop { ifnot lock: lock = true; critical_section; lock = false; } T2 T3T1 Shared Memory lock:
  • 12.
    Attempted Fix 11 loop { iflock == 0: lock = i; if lock == i: critical_section; lock = 0; } T2 T3T1 Shared Memory lock:
  • 13.
    Attempted Fix ofFix 12 loop { if lock1 == 0: lock1 = i; if lock1 == i: if lock2 == 0: lock2 = i; if lock2 == i: critical_section; lock2 = 0; lock1 = 0; } T2 T3T1 Shared Memory lock1: lock2:
  • 14.
    Attempted Fix ofFix of Fix … 13 loop { if lock1 == 0: lock1 = i; if lock1 == i: if lock2 == 0: lock2 = i; if lock2 == i: critical_section; lock2 = 0; lock1 = 0; } T2 T3T1 Shared Memory lock1: lock2: Do we need to see why 3-locks still breaks?
  • 15.
    Uniprocessor Easy (Kernel Cheating)Solution 14 loop { non-critical; disable interrupts critical_section; enable interrupts } T2 T3T1 Shared Memory
  • 16.
  • 17.
  • 18.
    Uniprocessor Easy (Kernel Cheating)Solution 17 loop { non-critical; disable interrupts critical_section; enable interrupts } T2 T3T1 Shared Memory How well does this solution work for modern kernels?
  • 19.
    Easy (Cheating) Solution 18 T2T3T1 Shared Memory (with atomic read/write/test&set) lock: test_and_set(v) returns current value of v sets value of v to true
  • 20.
    Easy (Cheating) Solution 19 loop{ if not test_and_set(lock): critical_section; lock = false; } T2 T3T1 Shared Memory (with atomic read/write/test&set) lock: test_and_set(v) returns current value of v sets value of v to true
  • 21.
    Does your processorprovide such an instruction? 20
  • 22.
  • 23.
  • 24.
  • 25.
    Implementing a MutexLock 24 lock_mutex(lock); critical unlock_mutex(lock); LDREX <dest> <location> <dest> = <location> Sets monitor on <location> in Exclusive state STREX <success> <value> <location> Conditionally store <value> into exclusive <location>. If permitted, <success> = 1 and <location> = <value>. If not, <success> = 0 and <location> value unchanged. Context switch clears monitor (Open) state.
  • 26.
    25 lock_mutex(lock); critical unlock_mutex(lock); lock_mutex(lock): try_again: LDREX R2, [lock] ifR2 goto try_again STREX R2, 1, [lock] if not R2 goto try_again unlock_mutex(lock): STR [lock], 0 LDREX <dest> <location> <dest> = <location> Sets monitor on <location> in Exclusive state STREX <success> <value> <location> Conditionally store <value> into exclusive <location>. If permitted, <success> = 1 and <location> = <value>. If not, <success> = 0 and <location> value unchanged.
  • 27.
    26 lock_mutex(lock); critical unlock_mutex(lock); lock_mutex(lock): try_again: LDREX R2, [lock] ifR2 goto try_again STREX R2, 1, [lock] if not R2 goto try_again unlock_mutex(lock): STR [lock], 0 What if you care about energy?
  • 28.
  • 29.
    28 WFE and WFIdo not provide synchronization! Just hints to the processor to save energy.
  • 30.
    29 ARMv7 Why two instructionslike this instead of one?
  • 31.
    30 T2 T3 T4T1 SharedMemory (atomic read and write) T5 Program: loop { non-critical { … } critical { … } } Requirements: 1. Only one thread may be in the critical section at any time. 2. Each must eventually be able to enter its critical section. 3. Must be symmetrical (all run same program). 4. Cannot make any assumptions about speed of threads. no special combined atomic operations (e.g., test-and-set, LDREX/STREX)
  • 32.
    31 Dijkstra (1973) From EdgarDaylight’s collection: http://www.dijkstrascry.com/node/59 1965
  • 33.
  • 34.
    33 Program for Processori loop { b[i] := false L1: if k != i c[i] := true if b[k] k := i goto L1 else: c[i] := false for j in [1, …, N]: if j != i and not c[j]: goto L1 critical section; c[i] := true b[i] := true } Initialization b[1:N] = [true, true, …] c[1:N] = [true, true, …] k = choose([1..N])
  • 35.
    34 Safety: only oneprogram can be in critical section Program for Processor i loop { b[i] := false L1: if k != i c[i] := true if b[k]: k := i goto L1 else: c[i] := false for j in [1, …, N]: if j != i and not c[j]: goto L1 critical section; c[i] := true b[i] := true }
  • 36.
    35 Program for Processori loop { b[i] := false L1: if k != i c[i] := true if b[k]: k := i goto L1 else: c[i] := false; L4: for j in [1, …, N]: if j != i and not c[j]: goto L1 critical section; c[i] := true b[i] := true } How do we know none of the c[.]’s changed during the loop?
  • 37.
    Charge Think about Dijkstra’sSolution: How does it guarantee mutual exclusion? How does it guarantee liveness? Submit Project Idea by 11:59pm Tonight 36