Barrier Synchronization Nir Shavit Multiprocessor Synchronization Spring 2003
Ideal Parallel Computation 1 1 1 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Ideal Parallel Computation 2 2 2 1 1 1 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Real-Life Parallel Computation zzz… 1 1 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Real-Life Parallel Computation 2 zzz… 1 1 Uh, oh 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barrier Synchronization barrier 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barrier Synchronization 1 1 1 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barrier Synchronization Until every thread has left here No thread enters here 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Why Do We Care? Mostly of interest to Elsewhere Scientific & numeric computation Elsewhere Garbage collection Rare in systems programming 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Number threads participating Barriers public class Barrier { int size; int count; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Number threads participating 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Number threads not yet arrived Barriers public class Barrier { int size; int count; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Number threads not yet arrived 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barriers public class Barrier { int size; int count; Initialization public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Initialization 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barriers public class Barrier { int size; int count; The method public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} The method 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
If I’m last, reset everything Barriers public class Barrier { int size; int count; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} If I’m last, reset everything 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Wait for rest to catch up Barriers public class Barrier { int size; int count; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Wait for rest to catch up 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
What’s wrong with this protocol? Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} What’s wrong with this protocol? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Reuse Barrier b = new Barrier(n); while ( mumble() ) { work(); b.await() } Do work repeat synchronize 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Waiting for Phase 1 to finish Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Waiting for Phase 1 to finish 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Waiting for Phase 1 to finish Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Phase 1 is so over Waiting for Phase 1 to finish 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchDec()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Prepare for phase 2 ZZZZZ…. 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Waiting for Phase 2 to finish Waiting for Phase 1 to finish Barriers public class Barrier { int count; int size; public Barrier(int n){ this.size = this.count = n; } public void await() { if (count.FetchInc()==1) { this.count = this.size; } else { while (this.count != 0) {} }}}} Waiting for Phase 2 to finish Waiting for Phase 1 to finish 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Basic Problem One thread “wraps around” to start phase 2 While another thread is still waiting for phase 1 One solution: Always use two barriers 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Sense-Reversing Barriers public class Barrier { int count, size; boolean sense = true; public void await(boolean mySense) { if (count.FetchDec()==1) { this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Sense-Reversing Barriers public class Barrier { int count, size; boolean sense = true; public void await(boolean mySense) { if (count.FetchDec()==1) { this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Completed odd or even-numbered phase? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Sense-Reversing Barriers public class Barrier { int count, size; boolean sense = true; public void await(boolean mySense) { if (count.FetchDec()==1) { this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Thread working on odd or even-numbered phase? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Sense-Reversing Barriers public class Barrier { int count, size; boolean sense = true; public void await(boolean mySense) { if (count.FetchDec()==1) { this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} If I’m last, reverse the sense on the way out 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Sense-Reversing Barriers public class Barrier { int count, size; boolean sense = true; public void await(boolean mySense) { if (count.FetchDec()==1) { this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Otherwise, wait for sense to flip 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barriers 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barriers 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Parent barrier in tree 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Thread working on odd or even-numbered phase? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Am I last? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense){ if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Wait on parent barrier, if any 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense){ if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Prepare for next phase 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} Wake up others at this level 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier public class CBarrier { int count, size; CBarrier parent; public void await(boolean mySense) { if (this.count.FetchDec()==1){ if (this.parent != null) this.parent.await(); this.count = this.size; this.sense = mySense } else { while (this.sense != mySense) {} }}}} I’m not last, wait for release 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Combining Tree Barrier No sequential bottleneck FetchDec calls proceed in parallel Low memory contention Same reason Cache behavior Local spinning on bus-based architecture Not so good for distributed 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Remarks Everyone spins on sense field Sequential bottleneck Local spinning on bus-based (good) Network hot-spot on distributed architecture (bad) Sequential bottleneck Sequence of FetchInc() calls Not really scalable 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barrier If tree nodes have fan-in 2 Don’t need to call FetchDec() Winner chosen statically At level i If i-th bit of id is zero, move up Otherwise keep back 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers winner loser winner loser winner loser 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers All flags blue 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Loser thread sets winner’s flag 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Loser spins on own flag 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Winner spins on own flag 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Winner sees own flag, moves up, spins 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Bingo! 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Tree Barriers Sense-reversing: next time use blue flags 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier class TBarrier { boolean flag; TBarrier partner; TBarrier parent; boolean top; … } 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Notifications delivered here Tournament Barrier class TBarrier { boolean flag; TBarrier partner; TBarrier parent; boolean top; … } Notifications delivered here 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Other thead at same level Tournament Barrier class TBarrier { boolean flag; TBarrier partner; TBarrier parent; boolean top; … } Other thead at same level 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Parent (winner) or null (loser) Tournament Barrier class TBarrier { boolean flag; TBarrier partner; TBarrier parent; boolean top; … } Parent (winner) or null (loser) 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier Am I the root? class TBarrier { boolean flag; TBarrier partner; TBarrier parent; boolean top; … } Am I the root? 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier The root, c’est moi void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} The root, c’est moi 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier I am already a winner void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} I am already a winner 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Wait for partner to show up Tournament Barrier void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} Wait for partner to show up 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier Synchronize upstairs void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} Synchronize upstairs 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier Notify partner void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} Notify partner 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
My thread is such a loser Tournament Barrier void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} My thread is such a loser 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Tournament Barrier Tell partner I’m here void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} Tell partner I’m here 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Wait for partner to release me Tournament Barrier void await(boolean mySense) { if (this.top) { return; } else if (this.parent != null) { while (this.flag[round] != mySense) {}; this.parent.await(mySense); this.partner.flag[round] = mysense; } else { this.partner.flag[round] = mySense; }}} Wait for partner to release me 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Remarks No need for read-modify-write calls Each thread spins on fixed location Good for bus-based architectures Good for distributed architectures 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier At round i Thread A notifies thread A+2i (mod n) Requires log n rounds 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier +1 +2 +4 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Details Use two copies of fields Avoids interference Use sense-reversing Avoid reinitializing fields Thread Arguments Parity of round Sense (flips when round becomes 0) 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier public class DBarrier { private boolean flags[2][logn]; private DBarrier partners[2][logn]; } 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier public class DBarrier { private boolean flags[2][logn]; private DBarrier partners[2][logn]; } Use two copies to avoid interference 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier public class DBarrier { private boolean flags[2][logn]; private DBarrier partners[2][logn]; } One element per round 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier public class DBarrier { private boolean flags[2][logn]; private DBarrier partners[2][logn]; } Notify me here 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier public class DBarrier { private boolean flags[2][logn]; private DBarrier partners[2][logn]; } Barrier for thread A + 2i 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier void await(int parity, boolean mySense) { for (int i=0; i<logn; i++) { this.partner[parity].flags[i] = mySense; while (this.flags[i] != mySense) {} } 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier void await(int parity, boolean mySense) { for (int i=0; i<logn; i++) { this.partner[parity].flags[i] = mySense; while (this.flags[i] != mySense) {} } Parity of current phase 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier void await(int parity, boolean mySense) { for (int i=0; i<logn; i++) { this.partner[parity].flags[i] = mySense; while (this.flags[i] != mySense) {} } Flips when parity becomes 0 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier void await(int parity, boolean mySense) { for (int i=0; i<logn; i++) { this.partner[parity].flags[i] = mySense; while (this.flags[i] != mySense) {} } Notify thread A+2i 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Dissemination Barrier void await(int parity, boolean mySense) { for (int i=0; i<logn; i++) { this.partner[parity].flags[i] = mySense; while (this.flags[i] != mySense) {} } Wait for thread A-2i 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Remarks Every thread spins in the same place Good for distributed implementations Works even if n not a power of 2 4-Feb-19 M. Herlihy & N. Shavit (c) 2003
Clip Art 4-Feb-19 M. Herlihy & N. Shavit (c) 2003