Foundations of Shared Memory Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified by Rajeev Alur for CIS 640 University of Pennsylvania Fundamentals • What is the weakest form of communication that supports mutual exclusion? • What is the weakest shared object that allows shared-memory computation? © 2007 Herlihy & Shavit 2 Alan Turing • Helped us understand what is and is not computable on a sequential machine. • Still best model available © 2007 Herlihy & Shavit 3 Turing Machine Finite State Controller Reads and Writes Infinite tape 1 0 1 1 0 1 0 © 2007 Herlihy & Shavit 4 Turing Computability 1 0 1 1 0 1 0 • Mathematical model of computation • What is (and is not) computable • Efficiency (mostly) irrelevant © 2007 Herlihy & Shavit 5 Shared-Memory Computability? Shared Memory 10011 • Mathematical model of concurrent computation • What is (and is not) concurrently computable • Efficiency (mostly) irrelevant © 2007 Herlihy & Shavit 6 Foundations of Shared Memory To understand modern multiprocessors we need to ask some basic questions … © 2007 Herlihy & Shavit 7 Foundations of Shared Memory To understand modern What is the weakest useful form of multiprocessors we need to ask shared memory? some basic questions … © 2007 Herlihy & Shavit 8 Foundations of Shared Memory To understand modern What is the weakest useful form of multiprocessors to ask What we canneed it do? shared memory? some basic questions … © 2007 Herlihy & Shavit 9 Foundations of Shared Memory To understand modern What is the weakest useful form of multiprocessors to ask What we canneed it do? shared memory? What can’t it do? some basic questions … © 2007 Herlihy & Shavit 10 Register * Holds a (binary) value 10011 * A memory location: name is historical © 2007 Herlihy & Shavit 11 Register Can be read 10011 10011 © 2007 Herlihy & Shavit 12 Register Can be written 01100 10011 © 2007 Herlihy & Shavit 13 Registers public interface Register<T> { public T read(); public void write(T v); } © 2007 Herlihy & Shavit 14 Registers public interface Register<T> { public T read(); public void write(T v); } Type of register (usually Boolean or m-bit Integer) © 2007 Herlihy & Shavit 15 Single-Reader/Single-Writer Register 10011 01100 10011 © 2007 Herlihy & Shavit 16 Multi-Reader/Single-Writer Register 10011 01100 10011 © 2007 Herlihy & Shavit 17 Multi-Reader/Multi-Writer Register mumble 10011 mumble mumble 10011 01010 10011 11011 © 2007 Herlihy & Shavit 18 Jargon Watch • SRSW – Single-reader single-writer • MRSW – Multi-reader single-writer • MRMW – Multi-reader multi-writer © 2007 Herlihy & Shavit 19 Safe Register OK if reads and writes don’t overlap write(1001) read(1001) (2) © 2007 Herlihy & Shavit 20 Safe Register write(1001) Some valid value if reads and writes do overlap read(????) 0000 1001 © 2007 Herlihy & Shavit $*&v 1111 21 Regular Register write(0) write(1) read(1) read(0) • Single Writer • Readers return: – Old value if no overlap (safe) – Old or one of new values if overlap © 2007 Herlihy & Shavit 22 Regular or Not? write(0) write(1) read(1) read(0) © 2007 Herlihy & Shavit 23 Regular or Not? write(0) write(1) read(1) read(0) Overlap: returns new value © 2007 Herlihy & Shavit 24 Regular or Not? write(0) write(1) read(0) Overlap: returns old value © 2007 Herlihy & Shavit 25 Regular or Not? write(0) write(1) read(1) read(0) © 2007 Herlihy & Shavit 26 Regular ≠ Linearizable write(0) write(1) read(1) read(0) explain this! write(1) already happened © 2007 Herlihy & Shavit 27 Atomic Register write(1001) write(1010) read(1001) read(1010) read(1010) Linearizable to sequential safe register © 2007 Herlihy & Shavit 28 Atomic Register write(1001) write(1010) read(1001) read(1010) read(1010) © 2007 Herlihy & Shavit 29 Register Space MRMW MRSW SRSW Safe M-valued Boolean Regular Atomic © 2007 Herlihy & Shavit 30 Weakest Register Single writer 1 Single reader 0 1 Safe Boolean register © 2007 Herlihy & Shavit 31 Weakest Register Single writer Single reader 0 1 0 flipflop 0 1 0 Get correct reading if not during state transition © 2007 Herlihy & Shavit 32 Results • From SRSW safe Boolean register – All the other registers – Mutual exclusion • But not everything! – Consensus hierarchy (2) © 2007 Herlihy & Shavit 33 Locking within Registers • Not interesting to rely on mutual exclusion in register constructions • We want registers to implement mutual exclusion! • No fun to use mutual exclusion to implement itself! © 2007 Herlihy & Shavit 34 Wait-Free Implementations Definition: An object implementation is wait-free if every thread completes a method in a finite number of steps No mutual exclusion – Thread could halt in critical section – Build mutual exclusion from registers © 2007 Herlihy & Shavit 35 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 36 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit Next 37 Register Names public class SafeBoolMRSWRegister implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } (3) © 2007 Herlihy & Shavit 38 Register Names public class SafeBoolMRSWRegister implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } property (3) © 2007 Herlihy & Shavit 39 Register Names public class SafeBoolMRSWRegister implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } property Size matters (3) © 2007 Herlihy & Shavit 40 Register Names public class SafeBoolMRSWRegister implements Register<Boolean> { public boolean read() { … } public void write(boolean x) { … } } property type (3) How many readers & writers? © 2007 Herlihy & Shavit 41 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements Register<Boolean> { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} (2) © 2007 Herlihy & Shavit 42 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); Each thread }} has own safe SRSW register (2) © 2007 Herlihy & Shavit 43 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); write method }} (2) © 2007 Herlihy & Shavit 44 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { Write each int i = ThreadID.get(); thread’s register return r[i].read(); one at a time }} (2) © 2007 Herlihy & Shavit 45 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); read } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} (2) © 2007 Herlihy & Shavit method 46 Safe Boolean MRSW from Safe Boolean SRSW public class SafeBoolMRSWRegister implements BooleanRegister { private SafeBoolSRSWRegister[] r = new SafeBoolSRSWRegister[N]; public void write(boolean x) { for (int j = 0; j < N; j++) r[j].write(x); } public boolean read() { int i = ThreadID.get(); return r[i].read(); }} (2) © 2007 Herlihy & Shavit Read my own register 47 Safe Boolean MRSW from Safe Boolean SRSW 1 0 1 1 0 0 1 0 or 1 0 0 1 © 2007 Herlihy & Shavit 48 Q: Safe Multi-Valued MRSW Safe Multi-Valued SRSW? 1 0 1 1011 1000 1011 Any value in range 0 1000 1000 © 2007 Herlihy & Shavit 49 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular Questions? MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 50 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit Next 51 Regular Boolean MRSW from Safe Boolean MRSW Safe register can return 0 or 1 even if the same value is written 1 1 0 © 2007 Herlihy & Shavit Regular: But if only it changed, old value OKifto read not0 or changed 1 52 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean> { private boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); }} (2) © 2007 Herlihy & Shavit 53 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; Last bit this thread wrote (OK, we’re cheating here on Java syntax) }} public boolean read() { return value.read(); }} (2) © 2007 Herlihy & Shavit 54 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { return value.read(); Actual value }} (2) © 2007 Herlihy & Shavit 55 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); Is new value different old = x; from last value I wrote? }} public boolean read() { return value.read(); }} (2) © 2007 Herlihy & Shavit 56 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean> { threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { value.write(x); old = x; }} public boolean read() { If so, change it return value.read(); }} (otherwise don’t!) (2) © 2007 Herlihy & Shavit 57 Regular Boolean MRSW from Safe Boolean MRSW public class RegBoolMRSWRegister implements Register<Boolean>{ threadLocal boolean old; private SafeBoolMRSWRegister value; public void write(boolean x) { if (old != x) { •Overlap? No Overlap? value.write(x); •No problem old = x; •either Boolean value works }} public boolean read() { return value.read(); }} (2) © 2007 Herlihy & Shavit 58 Regular Multi-Valued MRSW to Safe Multi-Valued MRSW? Safe register can return value in range other than old or new when value changes 1 0101 © 2007 Herlihy & Shavit 1 Multivalued Regular register can return only old or new when value changes! 59 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic Questions? MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 60 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit Next 61 MRSW Regular M-valued from MRSW Regular Boolean public class RegMRSWRegister implements Register{ RegBoolMRSWRegister[M] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} © 2007 Herlihy & Shavit 62 MRSW Regular M-valued from MRSW Regular Boolean public class RegMRSWRegister implements Register{ RegBoolMRSWRegister[M] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } Unary representation: bit[i] means value i public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} © 2007 Herlihy & Shavit 63 MRSW Regular M-valued from MRSW Regular Boolean public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} (1) © 2007 Herlihy & Shavit Set bit x 64 MRSW Regular M-valued from MRSW Regular Boolean public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; public void write(int x) { this.bit[x].write(true); for (int i=x-1; i>=0; i--) this.bit[i].write(false); } public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} (1) Clear bits from higher to lower © 2007 Herlihy & Shavit 65 MRSW Regular M-valued from MRSW Regular Boolean public class RegMRSWRegisterimplements Register { RegBoolMRSWRegister[m] bit; Scan from public void write(int x) { this.bit[x].write(true); to higher & for (int i=x-1; i>=0; i--) this.bit[i].write(false); first bit } lower return set public int read() { for (int i=0; i < M; i++) if (this.bit[i].read()) return i; }} (1) © 2007 Herlihy & Shavit 66 Writing M-Valued Write 5 Initially 0 0 1 0 0 0 1 01234567 © 2007 Herlihy & Shavit 67 Writing M-Valued Write 5 0 0 1 0 0 0 1 5 01234567 © 2007 Herlihy & Shavit 68 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 69 Road Map (Slight Detour) • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular SRSW Atomic MRSW atomic MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 70 SRSW Atomic From SRSW Regular Regular writer 1234 5678 1234 Regular reader Instead of 5678… When is this a problem? © 2007 Herlihy & Shavit 71 SRSW Atomic From SRSW Regular Regular writer 1234 5678 Initially 1234 5678 Regular reader Reg write(5678) Reg read(5678) time © 2007 Herlihy & Shavit 72 SRSW Atomic From SRSW Regular Regular writer 1234 5678 Initially 1234 1234 Regular reader Instead of 5678… Reg write(5678) Reg read(1234) time © 2007 Herlihy & Shavit 73 SRSW Atomic From SRSW Regular Regular writer 1234 5678 Initially 1234 1234 Regular reader Instead of 5678… Reg write(5678) Reg read(5678) Write time 5678 happened Reg read(1234) © 2007 Herlihy & Shavit 74 Timestamped Values 1234 1:45 5678 2:00 Writer writes value and stamp together © 2007 Herlihy & Shavit 2:00 5678 Reader saves last reads (value,stamp) and returns new value only if higher stamp 75 SRSW Atomic From SRSW writer Regular reader 1:45 2:00 1:45 1234 1234 5678 Reg write(2:00 5678) read(1:45 1234) > read(2:00 5678) 1:45 1234 Less than 2:00 5678 So stick with 5678 time old = 2:00 5678 © 2007 Herlihy & Shavit 76 Atomic Single Reader to Atomic Multi-Reader stamp value 1:45 1:45 1:45 1:45 1234 1234 1234 1234 © 2007 Herlihy & Shavit One per reader 77 Another Scenario Writer starts write… stamp value 2:00 1:45 1:45 1:45 5678 1234 1234 1234 © 2007 Herlihy & Shavit 78 Another Scenario 2:00, 5678 zzz… stamp value 2:00 1:45 1:45 1:45 5678 1234 1234 1234 reader reads later reader 1:45 1234 Yellow was completely after blue but read earlier value…not linearizable! © 2007 Herlihy & Shavit 79 Multi-Reader Redux One per thread 1 1:45 1:45 1:45 2 1234 1234 1234 1:45 1:45 1:45 3 1234 1234 1234 © 2007 Herlihy & Shavit 1:45 1:45 1:45 1234 1234 1234 1 2 3 80 Writer writes column… 2:00, 5678 Multi-Reader Redux reader reads row 1 1 1:45 2:00 1:45 2:00 2:00 1:45 2 1234 5678 1234 5678 5678 1234 1:45 1:45 1:45 2 3 1234 1234 1234 © 2007 Herlihy & Shavit 1:45 1:45 1:45 1234 1234 1234 1 2 3 81 2:00, 5678 Multi-Reader Redux zzz…after second write reader writes column to 1 notify others of what it 2 read 1 2 3 1:45 1234 1:45 1234 2:00 5678 1:45 1234 1 2:00 5678 1:45 1234 1:45 1234 2:00 5678 1:45 1234 2 2:00 5678 1:45 1234 2:00 1:45 5678 1234 1:45 1234 3 Yellow reader will read new value in column written by earlier Blue reader © 2007 Herlihy & Shavit 82 Can’t Yellow Miss Blue’s Update? … Only if Readers Overlap… 1:45 1234 write(2:00 5678) read(2:00 5678) read(1:45 1234) In which case time its OK to read 1234 © 2007 Herlihy & Shavit 83 Bad Case Only When Readers Don’t Overlap 1:45 1234 write(2:00 5678) read(2:00 5678) In which case Blue will complete writing 2:00 5678 to its column read(2:00 5678) time © 2007 Herlihy & Shavit 84 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic Next MRMW atomic Atomic snapshot © 2007 Herlihy & Shavit 85 Multi-Writer Atomic From Multi-Reader Atomic Each writer reads all then writes Max+1 to its register stamp value 1:45 1:45 2:00 1:45 2:15 1:45 1234 1234 5678 1234 XYZW 1234 Readers read all and take max (Lexicographic like Bakery) Max is 2:15, return XYZW © 2007 Herlihy & Shavit 86 Atomic Execution Means its Linearizable write(1) write(2) Read (max = 1) Read(max= 2) write(4) write(3) write(2) Read(max = 3) Read(max = 4) time (4) © 2007 Herlihy & Shavit 87 Linearization Points write(1) write(2) Read (max = 1) Read(max= 2) write(4) write(3) write(2) Read(max = 3) Read(max = 4) time (4) © 2007 Herlihy & Shavit 88 Linearization Points Look at Writes First write(1) write(2) write(4) write(3) write(2) time (4) © 2007 Herlihy & Shavit 89 Linearization Points Order writes by TimeStamp write(1) write(2) write(4) write(3) write(2) time (4) © 2007 Herlihy & Shavit 90 Linearization Points Order reads by max stamp read write(1) write(2) Read (max = 1) Read(max= 2) write(4) write(3) write(2) Read(max = 3) Read(max = 4) time (4) © 2007 Herlihy & Shavit 91 Linearization Points Order reads by max stamp read write(1) write(2) Read (max = 1) Read(max= 2) write(4) write(3) write(2) Read(max = 3) Read(max = 4) time (4) © 2007 Herlihy & Shavit 92 Linearization Points The linearization point depends on the execution (not a line in the code)! write(1) write(2) Read (max = 1) Read(max= 2) write(4) write(3) write(2) Read(max = 3) Read(max = 4) time (4) © 2007 Herlihy & Shavit 93 Road Map • • • • • • • SRSW safe Boolean MRSW safe Boolean MRSW regular Boolean MRSW regular MRSW atomic MRMW atomic Next Atomic snapshot © 2007 Herlihy & Shavit 94 Atomic Snapshot update © 2007 Herlihy & Shavit scan 95 Atomic Snapshot • Array of SWMR atomic registers • Take instantaneous snapshot of all • Generalizes to MRMW registers … © 2007 Herlihy & Shavit 96 Snapshot Interface public interface Snapshot { public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit 97 Snapshot Interface Thread i writes v to its register public interface Snapshot { public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit 98 Snapshot Interface Instantaneous snapshot of all theads’ registers public interface Snapshot { public int update(int v); public int[] scan(); } (2) © 2007 Herlihy & Shavit 99 Atomic Snapshot • Collect – Read values one at a time • Problem – Incompatible concurrent collects – Result not linearizable © 2007 Herlihy & Shavit 100 Clean Collects • Clean Collect – Collect during which nothing changed – Can we make it happen? – Can we detect it? © 2007 Herlihy & Shavit 101 Simple Snapshot • Put increasing labels on each entry • Collect twice • If both agree, – We’re done • Otherwise, – Try again Collect2 Collect1 1 1 22 1 22 1 7 = 7 13 13 18 12 18 12 © 2007 Herlihy & Shavit 102 Simple Snapshot: Update public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } (1) © 2007 Herlihy & Shavit 103 Simple Snapshot: Update public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } One single-writer register per thread (1) © 2007 Herlihy & Shavit 104 Simple Snapshot: Update public class SimpleSnapshot implements Snapshot { private AtomicMRSWRegister[] register; public void update(int value) { int i = Thread.myIndex(); LabeledValue oldValue = register[i].read(); LabeledValue newValue = new LabeledValue(oldValue.label+1, value); register[i].write(newValue); } Write each time with higher label (1) © 2007 Herlihy & Shavit 105 Simple Snapshot: Collect private LabeledValue[] collect() { LabeledValue[] copy = new LabeledValue[n]; for (int j = 0; j < n; j++) copy[j] = this.register[j].read(); return copy; } (1) © 2007 Herlihy & Shavit 106 Simple Snapshot private LabeledValue[] collect() { LabeledValue[] copy = new LabeledValue[n]; for (int j = 0; j < n; j++) copy[j] = this.register[j].read(); return copy; } Just read each register into array (1) © 2007 Herlihy & Shavit 107 Simple Snapshot: Scan public int[] scan() { LabeledValue[] oldCopy, newCopy; oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} (1) © 2007 Herlihy & Shavit 108 Simple Snapshot: Scan public int[] scan() { LabeledValue[] oldCopy, newCopy; Collect oldCopy = collect(); collect: while (true) { newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} (1) © 2007 Herlihy & Shavit once 109 Simple Snapshot: Scan public int[] scan() { LabeledValue[] oldCopy, newCopy; Collect once oldCopy = collect(); collect: while (true) { Collect twice newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} return getValues(newCopy); }}} (1) © 2007 Herlihy & Shavit 110 Simple Snapshot: Scan public int[] scan() { LabeledValue[] oldCopy, newCopy; Collect once oldCopy = collect(); collect: while (true) { Collect twice newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; }} On mismatch, return getValues(newCopy); try again }}} (1) © 2007 Herlihy & Shavit 111 Simple Snapshot: Scan public int[] scan() { LabeledValue[] oldCopy, newCopy; Collect once oldCopy = collect(); collect: while (true) { Collect twice newCopy = collect(); if (!equals(oldCopy, newCopy)) { oldCopy = newCopy; continue collect; On match, return }} values return getValues(newCopy); }}} (1) © 2007 Herlihy & Shavit 112 Simple Snapshot • Linearizable • Update is wait-free – No unbounded loops • But Scan can starve – If interrupted by concurrent update © 2007 Herlihy & Shavit 113 Wait-Free Snapshot • Add a scan before every update • Write resulting snapshot together with update value • If scan is continuously interrupted by updates, scan can take the update’s snapshot © 2007 Herlihy & Shavit 114 Wait-free Snapshot If A’s scan observes that B moved twice, then B completed an update while A’s scan was in progress Collect Collect Collect 26 24 12 26 24 12 26 24 12 B ≠ ≠ Update time © 2007 Herlihy & Shavit 115 Wait-free Snapshot A Collect Collect Collect 26 24 12 26 24 12 26 24 12 B ≠ ≠ Update time © 2007 Herlihy & Shavit 116 Wait-free Snapshot A Collect Collect Collect 26 24 12 26 24 12 26 24 12 B ≠ Scan Update ≠ Write time © 2007 Herlihy & Shavit 117 Wait-free Snapshot A Collect Collect Collect 26 24 12 26 24 12 26 24 12 B ≠ Scan Update ≠ Write A can steal result of B’s scan time © 2007 Herlihy & Shavit 118 Once is not Enough A B Scan Update Collect Collect 26 24 12 26 24 12 ≠ Write Can A steal result of B’s scan? time © 2007 Herlihy & Shavit 119 Once is not Enough A B Scan Collect 26 24 12 26 24 12 ≠ Write Update C Collect No time © 2007 Herlihy & Shavit 120 Someone Must Move Twice Collect Collect Collect 26 24 12 26 24 12 26 24 12 B ≠ ≠ Update time Why are scans wait-free? © 2007 Herlihy & Shavit 121 Wait-Free Snapshot Label public class SnapValue { public int label; public int value; public int[] snap; } (2) © 2007 Herlihy & Shavit 122 Wait-Free Snapshot Label public class SnapValue { public int label; public int value; public int[] snap; } Counter incremented with each snapshot (2) © 2007 Herlihy & Shavit 123 Wait-Free Snapshot Label public class SnapValue { public int label; public int value; public int[] snap; } Actual value (2) © 2007 Herlihy & Shavit 124 Wait-Free Snapshot Label public class SnapValue { public int label; public int value; public int[] snap; } most recent snapshot (2) © 2007 Herlihy & Shavit 125 Wait-free Update public void update(int value) { int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); } (2) © 2007 Herlihy & Shavit 126 Wait-free Scan public void update(int value) { Take scan int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); } (2) © 2007 Herlihy & Shavit 127 Wait-free Scan public void update(int value) { Take scan int i = Thread.myIndex(); int[] snap = this.scan(); SnapValue oldValue = r[i].read(); SnapValue newValue = new SnapValue(oldValue.label+1, value, snap); r[i].write(newValue); Label value with scan } (2) © 2007 Herlihy & Shavit 128 Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { … Keep track of who moved }} return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit 129 Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { … }} return getValues(newCopy); }}} Repeated double collect (2) © 2007 Herlihy & Shavit 130 Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { … }} return getValues(newCopy); }}} (2) If mismatch detected…lets expand © 2007 Herlihy & Shavit here… 131 Mismatch Detected if (oldCopy[j].label != newCopy[j].label) { if (moved[j]) { // second move return oldCopy[j].snap; } else { moved[j] = true; oldCopy = newCopy; continue collect; }}} return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit 132 Mismatch Detected if (oldCopy[j].label != newCopy[j].label) { if (moved[j]) { return oldCopy[j].snap; } else { moved[j] = true; oldCopy = newCopy; continue collect; If thread moved twice, }}} just steal its snapshot return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit 133 Mismatch Detected if (oldCopy[j].label != newCopy[j].label) { if (moved[j]) { // second move return oldCopy[j].snap; } else { moved[j] = true; Remember that oldCopy = newCopy; thread moved continue collect; }}} return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit 134 Wait-free Scan public int[] scan() { SnapValue[] oldCopy, newCopy; boolean[] moved = new boolean[n]; oldCopy = collect(); collect: while (true) { newCopy = collect(); for (int j = 0; j < n; j++) { if (oldCopy[j].label != newCopy[j].label) { … }} return getValues(newCopy); }}} (2) © 2007 Herlihy & Shavit 135 Wait-free scan At most n-1 depth update scan update scan So some thread must have had clean collect © 2007 Herlihy & Shavit 136 Observations • Uses unbounded counters – can be replaced with 2 bits • Assumes SWMR registers – for labels – can be extended to MRMW © 2007 Herlihy & Shavit 137 Summary • We saw we could implement MRMW multi valued snapshot objects • From SRSW binary safe registers (simple flipflops) • But what is the next step to attempt with read-write registers? © 2007 Herlihy & Shavit 138 Consensus: Each Thread has a Private Input 19 32 21 © 2007 Herlihy & Shavit 139 They Communicate © 2007 Herlihy & Shavit 140 They Agree on One Thread’s Input 19 19 19 © 2007 Herlihy & Shavit 141 Formally: Consensus • Consistent: – all threads decide the same value • Valid: – the common decision value is some thread's input © 2007 Herlihy & Shavit 142 No Wait-Free Implementation of Consensus using Registers ??? ??? © 2007 Herlihy & Shavit 143 Formally • Theorem – There is no wait-free implementation of n-thread consensus from read-write registers • Implication – Asynchronous computability different from Turing computability © 2007 Herlihy & Shavit 144 Proof Strategy • Assume otherwise • Reason about the properties of any such protocol • Derive a contradiction • Suffices to prove for binary consensus and n=2 © 2007 Herlihy & Shavit 145 Wait-Free Computation A moves B moves • Either A or B “moves” • Moving means – Register read – Register write © 2007 Herlihy & Shavit 146 The Two-Move Tree Final states Initial state © 2007 Herlihy & Shavit 147 Decision Values 1 0 0 1 © 2007 Herlihy & Shavit 1 1 148 Bivalent: Both Possible bivalent 1 0 0 1 © 2007 Herlihy & Shavit 1 1 149 Univalent: Single Value Possible univalent 1 0 0 1 © 2007 Herlihy & Shavit 1 1 150 x-valent: x Only Possible Decision 1-valent 1 0 0 1 © 2007 Herlihy & Shavit 1 1 151 Summary • Wait-free computation is a tree • Bivalent system states – Outcome not fixed • Univalent states – Outcome is fixed – May not be “known” yet • 1-Valent and 0-Valent states © 2007 Herlihy & Shavit 152 Claim • Some initial state is bivalent • Outcome depends on – Chance – Whim of the scheduler … • Lets prove it … © 2007 Herlihy & Shavit 153 Both Inputs 0 0 0 Univalent: all executions must decide 0 © 2007 Herlihy & Shavit 154 Both Inputs 0 0 Including this solo execution by A © 2007 Herlihy & Shavit 155 Both Inputs 1 1 1 All executions must decide 1 © 2007 Herlihy & Shavit 156 Both Inputs 1 1 Including this solo execution by B © 2007 Herlihy & Shavit 157 What if inputs differ? 0 1 By Way of contradiction: If univalent all executions must decide on same value © 2007 Herlihy & Shavit 158 Critical States critical 0-valent 1-valent © 2007 Herlihy & Shavit 159 From a Critical State c 0-valent If A goes first, protocol decides 0 1-valent If B goes first, protocol decides 1 © 2007 Herlihy & Shavit 160 Reaching Critical State CB CA initially bivalent univalent CB univalent CA univalent c univalent 0-valent 1-valent © 2007 Herlihy & Shavit 161 Critical States • Starting from a bivalent initial state • The protocol can reach a critical state – Otherwise we could stay bivalent forever – And the protocol is not wait-free © 2007 Herlihy & Shavit 162 Model Dependency • So far, memory-independent! • True for – – – – Registers Message-passing Carrier pigeons Any kind of asynchronous computation © 2007 Herlihy & Shavit 163 Read-Write Memory • Reads and/or writes • To same/different registers © 2007 Herlihy & Shavit 164 Completing the Proof • Lets look at executions that: – Start from a critical state – Threads cause state to become univalent by reading or writing to same/different registers – End within a finite number of steps deciding either 0 or 1 • Show this leads to a contradiction © 2007 Herlihy & Shavit 165 Possible Interactions A reads x A reads y x.read() y.read() x.write() y.write() x.read() ? ? ? ? y.read() ? ? ? ? x.write() ? ? ? ? y.write() ? ? ? ? © 2007 Herlihy & Shavit 166 Some Thread Reads A runs solo, eventually decides 0 c B reads x 0 1 States look the same to A © 2007 Herlihy & Shavit A runs solo, eventually decides 1 167 Possible Interactions x.read() y.read() x.write() y.write() x.read() no no no no y.read() no no no no x.write() no no ? ? y.write() no no ? ? © 2007 Herlihy & Shavit 168 Writing Distinct Registers A writes y c B writes x A writes y B writes x 0 1 Same story © 2007 Herlihy & Shavit 169 Possible Interactions x.read() y.read() x.write() y.write() x.read() no no no no y.read() no no no no x.write() no no ? no y.write() no no no ? © 2007 Herlihy & Shavit 170 Writing Same Registers A writes x c A runs solo, eventually decides 0 A writes x 0 States look the same to A B writes x 1 A runs solo, eventually decides 1 © 2007 Herlihy & Shavit 171 That’s All, Folks! x.read() y.read() x.write() y.write() x.read() no no no no y.read() no no no no x.write() no no no no y.write() no no no no © 2007 Herlihy & Shavit 172 Recap: Atomic Registers Can’t Do Consensus • If protocol exists – It has a bivalent initial state – Leading to a critical state • What’s up with the critical state? – Case analysis for each pair of methods – As we showed, all lead to a contradiction © 2007 Herlihy & Shavit 173 What Does Consensus have to do with Concurrent Objects? © 2007 Herlihy & Shavit 174 Consensus Object public interface Consensus { Object decide(object value); } © 2007 Herlihy & Shavit 175 Concurrent Consensus Object • We consider only one time objects: – each thread calls method only once • Linearizable to consensus object: – Winner’s call went first © 2007 Herlihy & Shavit 176 Generic Consensus Protocol abstract class ConsensusProtocol<T> implements Consensus { protected T[] proposed = new T[N]; protected void propose(T value) { proposed[ThreadID.get()] = value; } abstract public T decide(T value); } © 2007 Herlihy & Shavit 177 Generic Consensus Protocol abstract class ConsensusProtocol<T> implements Consensus { protected T[] proposed = new T[N]; protected void propose(T value) { proposed[ThreadID.get()] = value; } Each thread’s proposed value abstract public T decide(T value); } © 2007 Herlihy & Shavit 178 Generic Consensus Protocol abstract class ConsensusProtocol<T> implements Consensus { protected T[] proposed = new T[N]; protected void propose(T value) { proposed[ThreadID.get()] = value; } abstract public T decide(T value); } Propose a value © 2007 Herlihy & Shavit 179 Generic Consensus Protocol abstract class ConsensusProtocol<T> Decide a value: abstract method implements Consensus { means subclass does the heavy lifting protected T[] proposed = new T[N]; (real work) protected void propose(T value) { proposed[ThreadID.get()] = value; } abstract public T decide(T value); } © 2007 Herlihy & Shavit 180 Can a FIFO Queue Implement Consensus? © 2007 Herlihy & Shavit 181 FIFO Consensus proposed array FIFO Queue with red and black balls 8 Coveted red ball Dreaded black ball © 2007 Herlihy & Shavit 182 Protocol: Write Value to Array 0 0 © 2007 Herlihy & Shavit 1 183 Protocol: Take Next Item from Queue 0 8 0 1 © 2007 Herlihy & Shavit 184 Protocol: Take Next Item from Queue I got the 0 coveted 1 red ball, so I will decide my value I got the dreaded black ball, so I will decide the other’s value from the array 8 © 2007 Herlihy & Shavit 185 Consensus Using FIFO Queue public class QueueConsensus extends ConsensusProtocol { private Queue queue; public QueueConsensus() { queue = new Queue(); queue.enq(Ball.RED); queue.enq(Ball.BLACK); } … } © 2007 Herlihy & Shavit 186 Initialize Queue public class QueueConsensus extends ConsensusProtocol { private Queue queue; public QueueConsensus() { this.queue = new Queue(); this.queue.enq(Ball.RED); this.queue.enq(Ball.BLACK); } … } 8 © 2007 Herlihy & Shavit 187 Who Won? public class QueueConsensus extends ConsensusProtocol { private Queue queue; … public decide(object value) { propose(value); Ball ball = this.queue.deq(); if (ball == Ball.RED) return proposed[i]; else return proposed[1-i]; } } © 2007 Herlihy & Shavit 188 Who Won? public class QueueConsensus extends ConsensusProtocol { private Queue queue; … public decide(object value) { propose(value); Ball ball = this.queue.deq(); if (ball == Ball.RED) return proposed[i]; else return proposed[1-ij]; } Race to dequeue } first queue item © 2007 Herlihy & Shavit 189 Who Won? public class QueueConsensus extends ConsensusProtocol { private Queue queue; … public decide(object value) { propose(value); Ball ball = this.queue.deq(); if (ball == Ball.RED) return proposed[i]; else return proposed[1-i]; i = ThreadID.get(); } I win if I was } © 2007 Herlihy & Shavit first 190 Who Won? public class QueueConsensus extends ConsensusProtocol { private Queue queue; Other thread wins if … I was{ second public decide(object value) propose(value); Ball ball = this.queue.deq(); if (ball == Ball.RED) return proposed[i]; else return proposed[1-i]; } } © 2007 Herlihy & Shavit 191 Why does this Work? • • • • If one thread gets the red ball Then the other gets the black ball Winner decides her own value Loser can find winner’s value in array – Because threads write array before dequeueing from queue © 2007 Herlihy & Shavit 192 Theorem • We can solve 2-thread consensus using only – A two-dequeuer queue, and – Some atomic registers © 2007 Herlihy & Shavit 193 Implications • Given – A consensus protocol from queue and registers • Assume there exists – A queue implementation from atomic registers • Substitution yields: – A wait-free consensus protocol from atomic registers © 2007 Herlihy & Shavit 194 Corollary • It is impossible to implement – a two-dequeuer wait-free FIFO queue – from read/write memory. © 2007 Herlihy & Shavit 195 Consensus Numbers • An object X has consensus number n – If it can be used to solve n-thread consensus • Take any number of instances of X • together with atomic read/write registers • and implement n-thread consensus – But not (n+1)-thread consensus © 2007 Herlihy & Shavit 196 Consensus Numbers • Theorem – Atomic read/write registers have consensus number 1 • Theorem – Multi-dequeuer FIFO queues have consensus number at least 2 © 2007 Herlihy & Shavit 197 Consensus Numbers Measure Synchronization Power • Theorem – If you can implement X from Y – And X has consensus number c – Then Y has consensus number at least c © 2007 Herlihy & Shavit 198 Synchronization Speed Limit • Conversely – If X has consensus number c – And Y has consensus number d < c – Then there is no way to construct a wait-free implementation of X by Y • This theorem will be very useful – Unforeseen practical implications! © 2007 Herlihy & Shavit 199 Challenge Problem • Snapshot means – Write any array element – Read multiple array elements atomically • What about – Write multiple array elements atomically – Scan any array elements • Call this problem multiple assignment © 2007 Herlihy & Shavit 200 Multiple Assignment Theorem • Atomic registers cannot implement multiple assignment • Weird or what? – Single write/multi read OK – Multi write/multi read impossible © 2007 Herlihy & Shavit 201 Proof Strategy • If we can write to 2/3 array elements – We can solve 2-consensus – Impossible with atomic registers • Therefore – Cannot implement multiple assignment with atomic registers © 2007 Herlihy & Shavit 202 (1) Proof Strategy • Take a 3-element array – A writes atomically to slots 0 and 1 – B writes atomically to slots 1 and 2 – Any thread can scan any set of locations © 2007 Herlihy & Shavit 203 Double Assignment Interface interface Assign2 { public void assign(int i1, int v1, int i2, int v2); public int read(int i); } © 2007 Herlihy & Shavit 204 Double Assignment Interface interface Assign2 { public void assign(int i1, int v1, int i2, int v2); public int read(int i); } Atomically assign value[i1]= v1 value[i2]= v2 © 2007 Herlihy & Shavit 205 Double Assignment Interface interface Assign2 { public void assign(int i1, int v1, int i2, int v2); public int read(int i); } Return i-th value © 2007 Herlihy & Shavit 206 Initially A Writes to 0 and 1 B Writes to 1 and 2 © 2007 Herlihy & Shavit 207 Thread A wins if A Thread B didn’t move B © 2007 Herlihy & Shavit 208 Thread A wins if A Thread B moved later B © 2007 Herlihy & Shavit 209 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else return proposed[j]; }} © 2007 Herlihy & Shavit 210 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; Three slots else initialized to return proposed[j]; EMPTY }} © 2007 Herlihy & Shavit 211 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else Assign id 0 to return proposed[j]; entries 0,1 (or id 1 }} to entries 1,2) © 2007 Herlihy & Shavit 212 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else return proposed[j]; Read the register my }} thread didn’t assign © 2007 Herlihy & Shavit 213 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else return proposed[j]; Other thread didn’t move, so I win }} © 2007 Herlihy & Shavit 214 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else Other thread moved return proposed[j]; later so I win }} © 2007 Herlihy & Shavit 215 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i]; else return proposed[j]; OK, I win. }} © 2007 Herlihy & Shavit 216 Multi-Consensus Code class MultiConsensus extends …{ Assign2 a = new Assign2(3, EMPTY); public Object decide(object value) { a.assign(i, i, i+1, i); int other = a.read((i+2) % 3); if (other==EMPTY||other==a.read(1)) return proposed[i];(1) else return proposed[j];Other thread moved }} first, so I lose © 2007 Herlihy & Shavit 217 Summary • If a thread can assign atomically to 2 out of 3 array locations • Then we can solve 2-consensus • Therefore – No wait-free multi-assignment – From read/write registers © 2007 Herlihy & Shavit 218 Read-Modify-Write Objects • Method call – Returns object’s prior value x – Replaces x with mumble(x) © 2007 Herlihy & Shavit 219 Read-Modify-Write public abstract class RMWRegister { private int value; public int synchronized getAndMumble() { int prior = this.value; this.value = mumble(this.value); return prior; } } © 2007 Herlihy & Shavit 220 Read-Modify-Write public abstract class RMWRegister { private int value; public int synchronized getAndMumble() { int prior = this.value; this.value = mumble(this.value); return prior; } } Return prior value © 2007 Herlihy & Shavit 221 Read-Modify-Write public abstract class RMWRegister { private int value; public int synchronized getAndMumble() { int prior = this.value; this.value = mumble(this.value); return prior; } } Apply function to current value © 2007 Herlihy & Shavit 222 RMW Everywhere! • Most synchronization instructions – are RMW methods • The rest – Can be trivially transformed into RMW methods © 2007 Herlihy & Shavit 223 Example: Read public abstract class RMWRegister { private int value; public int synchronized read() { int prior = this.value; this.value = this.value; return prior; } } © 2007 Herlihy & Shavit 224 Example: Read public abstract class RMW { private int value; public int synchronized read() { int prior = this.value; this.value = this.value; return prior; } } Apply f(v)=v, the identity function © 2007 Herlihy & Shavit 225 Example: getAndSet public abstract class RMWRegister { private int value; public int synchronized getAndSet(int v) { int prior = this.value; this.value = v; return prior; } … } © 2007 Herlihy & Shavit 226 Example: getAndSet (swap) public abstract class RMWRegister { private int value; public int synchronized getAndSet(int v) { int prior = this.value; this.value = v; return prior; } F(x)=v is constant function … } © 2007 Herlihy & Shavit 227 getAndIncrement public abstract class RMWRegister { private int value; public int synchronized getAndIncrement() { int prior = this.value; this.value = this.value + 1; return prior; } … } © 2007 Herlihy & Shavit 228 getAndIncrement public abstract class RMWRegister { private int value; public int synchronized getAndIncrement() { int prior = this.value; this.value = this.value + 1; return prior; } … F(x) = x+1 } (1) © 2007 Herlihy & Shavit 229 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; } … } © 2007 Herlihy & Shavit 230 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; If value is what was } … } expected, … © 2007 Herlihy & Shavit 231 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; … replace it } … } © 2007 Herlihy & Shavit 232 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; Report success } … } © 2007 Herlihy & Shavit 233 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } Otherwise report return false; failure } … } © 2007 Herlihy & Shavit 234 Read-Modify-Write public abstract class RMWRegister { private int value; public void synchronized getAndMumble() { int prior = this.value; this.value = mumble(this.value); return prior; } } Lets characterize F(x)… © 2007 Herlihy & Shavit 235 Definition • A RMW method – With function mumble(x) – is non-trivial if there exists a value v – Such that v ≠ mumble(v) © 2007 Herlihy & Shavit 236 Par Example • Identity(x) = x – is trivial • getAndIncrement(x) = x+1 – is non-trivial © 2007 Herlihy & Shavit 237 Theorem • Any non-trivial RMW object has consensus number at least 2 • No wait-free implementation of RMW registers from atomic registers • Hardware RMW instructions not just a convenience © 2007 Herlihy & Shavit 238 Proof public class RMWConsensus extends ConsensusProtocol { private RMWRegister r = v; public Object decide(object value) { propose(value); if (r.getAndMumble() == v) return proposed[i]; else return proposed[j]; }} © 2007 Herlihy & Shavit 239 Proof public class RMWConsensus extends ConsensusProtocol { private RMWRegister r = v; public Object decide(object value) { propose(value); if (r.getAndMumble() == v) return proposed[i]; Initialized to v else return proposed[j]; }} © 2007 Herlihy & Shavit 240 Proof public class RMWConsensus extends Consensus { Am I first? private RMWRegister r = v; public Object decide(object value) { if (r.getAndMumble() == v) return proposed[i]; else return proposed[j]; }} © 2007 Herlihy & Shavit 241 Proof public class RMWConsensus extends ConsensusProtocol { private RMWRegister r = v; public Object decide(object value) { Yes, return propose(value); if (r.getAndMumble() == v) my input return proposed[i]; else return proposed[j]; }} © 2007 Herlihy & Shavit 242 Proof public class RMWConsensus extends ConsensusProtocol { private RMWRegister r = v; public Object decide(object value) { propose(value); if (r.getAndMumble() == v) No, return return proposed[i]; other’s input else return proposed[j]; }} (4) © 2007 Herlihy & Shavit 243 Proof • We have displayed – A two-thread consensus protocol – Using any non-trivial RMW object © 2007 Herlihy & Shavit 244 Interfering RMW • Let F be a set of functions such that for all fi and fj, either – Commute: fi(fj(v))=fj(fi(v)) – Overwrite: fi(fj(v))=fi(v) • Claim: Any set of RMW objects that commutes or overwrites has consensus number exactly 2 © 2007 Herlihy & Shavit 245 Examples • “test-and-set” getAndSet(1) f(v)=1 Overwrite fi(fj(v))=fi(v) • “swap” getAndSet(x) f(v,x)=x Overwrite fi(fj(v))=fi(v) • “fetch-and-inc” getAndIncrement() f(v)=v+1 Commute fi(fj(v))= fj(fi(v)) © 2007 Herlihy & Shavit 246 Meanwhile Back at the Critical State A about to apply fA B about to apply fB c 0-valent 1-valent © 2007 Herlihy & Shavit 247 Maybe the Functions Commute A applies fA c B applies fB B applies fB A applies fA C runs solo C runs solo 0-valent 0 1 © 2007 Herlihy & Shavit 1-valent 248 Maybe the Functions Commute A applies fA c B applies fB These states look the same to C B applies fB A applies fA C runs solo C runs solo 0-valent 0 1 © 2007 Herlihy & Shavit 1-valent 249 Maybe the Functions Overwrite A applies fA c B applies fB A applies fA C runs solo 0 C runs solo 1 0-valent © 2007 Herlihy & Shavit 1-valent 250 Maybe the Functions Overwrite These states look the same to C A applies fA c B applies fB A applies fA C runs solo 0 C runs solo 1 0-valent © 2007 Herlihy & Shavit 1-valent 251 Impact • Many early machines provided these “weak” RMW instructions – Test-and-set (IBM 360) – Fetch-and-add (NYU Ultracomputer) – Swap (Original SPARCs) • We now understand their limitations – But why do we want consensus anyway? © 2007 Herlihy & Shavit 252 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; } … } © 2007 Herlihy & Shavit 253 compareAndSet public abstract class RMWRegister { private int value; public boolean synchronized compareAndSet(int expected, int update) { int prior = this.value; if (this.value==expected) { this.value = update; return true; } return false; replace value if its what we } … } expected, … © 2007 Herlihy & Shavit 254 compareAndSet Has ∞ Consensus Number public class RMWConsensus extends ConsensusProtocol { private AtomicInteger r = new AtomicInteger(-1); public Object decide(object value) { propose(value); r.compareAndSet(-1,i); return proposed[r.get()]; } } © 2007 Herlihy & Shavit 255 compareAndSet Has ∞ Consensus Number public class RMWConsensus extends ConsensusProtocol { private AtomicInteger r = new AtomicInteger(-1); public Object decide(object value) { propose(value) r.compareAndSet(-1,i); return proposed[r.get()]; } } Initialized to -1 © 2007 Herlihy & Shavit 256 compareAndSet Has ∞ Consensus Number public class RMWConsensus extends ConsensusProtocol { private AtomicInteger Try r = to swap in new AtomicInteger(-1); my id public Object decide(object value) { propose(value); r.compareAndSet(-1,i); return proposed[r.get()]; } } © 2007 Herlihy & Shavit 257 compareAndSet Has ∞ Consensus Number public class RMWConsensus extends ConsensusProtocol { winner’s private AtomicInteger Decide r = new AtomicInteger(-1);preference public Object decide(object value) { propose(value); r.compareAndSet(-1,i); return proposed[r.get()]; } } © 2007 Herlihy & Shavit 258 The Consensus Hierarchy 1 Read/Write Registers, Snapshots… 2 getAndSet, getAndIncrement, … . . . ∞ compareAndSet,… © 2007 Herlihy & Shavit 259 Multiple Assignment • Atomic k-assignment • Solves consensus for 2k-2 threads • Every even consensus number has an object (can be extended to odd numbers) © 2007 Herlihy & Shavit 260