
CS636: Shared Memory Synchronization Swarnendu Biswas Semester 2018-2019-II CSE, IIT Kanpur Content influenced by many excellent references, see References slide for acknowledgements. What is the desired property? class Set { final Vector elems = new Vector(); void add(Object x) { if (!elems.contains(x)) { elems.add(x); } } } class Vector { synchronized void add(Object o) { ... } synchronized boolean contains(Object o) { ... } } CS636 Swarnendu Biswas 2 What is the desired property? Q.insert(elem): Q.remove(): atomic { atomic { while (Q.full()) {} while (Q.empty()) {} // Add elem to the Q // Return data from Q } } CS636 Swarnendu Biswas 3 Implementing Synchronization Patterns • Condition synchronization while ¬ condition // do nothing (spin) • Mutual exclusion lock:bool := false Lock.acquire(): Lock.release(): while TAS(&lock) lock := false // spin CS636 Swarnendu Biswas 4 Locks (Mutual Exclusion) public interface Lock { Lock mtx = new LockImpl(…); public void lock(); … public void unlock(); mtx.lock(); } try { … // body public class LockImpl } finally { implements Lock { mtx.unlock(); … } … } CS636 Swarnendu Biswas 5 Desired Synchronization Properties • Mutual exclusion or safety Critical sections on the same lock from different threads do not overlap • Livelock freedom If a lock is available, then some thread should be able to acquire it within bounded steps. CS636 Swarnendu Biswas 6 Desired Synchronization Properties • Deadlock freedom If some thread attempts to acquire the lock, then some thread should be able to acquire the lock • Starvation freedom • Every thread that acquires a lock eventually releases it • A lock acquire request must eventually succeed within bounded steps CS636 Swarnendu Biswas 7 Classic Mutual Exclusion Algorithms CS636 Swarnendu Biswas 8 Peterson’s Algorithm class PetersonLock { public void lock() { int i = ThreadID.get(); static volatile boolean[] flag = int j = 1-i; new boolean[2]; flag[i] = true; static volatile int victim; victim = i; while (flag[j] && victim == i) {} public void unlock() { } int i = ThreadID.get(); flag[i] = false; } } CS636 Swarnendu Biswas 9 Peterson’s Algorithm class PetersonLock { public void lock() { int i = ThreadID.get(); static volatile boolean[] flag = int j = 1-i; new boolean[2]; flag[i] = true; static volatile intIs thisvictim; algorithm correctvictim under = i ; sequential consistency?while (flag[j] && victim == i) {} public void unlock() { } int i = ThreadID.get(); flag[i] = false; } } CS636 Swarnendu Biswas 10 What could go wrong? class TwoThreadLockFlags { public void unlock() { int i = ThreadID.get(); static volatile boolean[] flag = new flag[i] = false; boolean[2]; } public void lock() { } int i = ThreadID.get(); flag[i] = true; while (flag[j]) {} // wait } CS636 Swarnendu Biswas 11 What could go wrong? class TwoThreadLockVolatile { public void unlock() { } static volatile int victim; } public void lock() { int i = ThreadID.get(); victim = i; // wait for the other while (victim == i) {} } CS636 Swarnendu Biswas 12 Filter Algorithm non-CS with n threads level=0 • There are n-1 waiting rooms n-1 threads level=1 called “levels” • One thread gets blocked at each level if many threads try to enter 2 threads level=n-2 CS level=n-1 CS636 Swarnendu Biswas 13 Filter Lock class FilterLock { public void unlock() { int me = ThreadID.get(); int[] level; level[me]= 0; volatile int[] victim; } public FilterLock() { level = new int[n]; victim = new int[n]; for (int i = 0; i < n; i++) { level[i] = 0; } } CS636 Swarnendu Biswas 14 Filter Lock public void lock() { int me = ThreadID.get(); for (int i = 1; i < n; i++) { level[me] = i; // visit level i victim[i] = me; // Thread me is a good guy! // spin while conflict exits while ((∃k != me) level[k] >= i && victim[i] == me) { } } } } CS636 Swarnendu Biswas 15 Fairness • Starvation freedom is good, but maybe threads shouldn’t wait too much… • For example, it would be great if we could order threads by the order in which they performed the first step of the lock() method CS636 Swarnendu Biswas 16 Bounded Waiting • Divide lock() method into two parts • Doorway interval (DA) – finishes in finite steps • Waiting interval (WA) – may take unbounded steps r-Bounded Waiting k j k j+r For threads A and B: if DA DB , then CSA CSB CS636 Swarnendu Biswas 17 Lamport’s Bakery Algorithm class Bakery implements Lock { public Bakery(int n) { flag = new boolean[n]; boolean[] flag; label = new Label[n]; Label[] label; for (int i = 0; i<n; i++) { flag[i] = false; public void unlock() { label[i] = 0; flag[ThreadID.get()] = false; } } } CS636 Swarnendu Biswas 18 Lamport’s Bakery Algorithm (label[i], i) << (label[j], j)) iff label[i] < label[j] or label[i] = label[j] and i < j public void lock() { int i = ThreadID.get(); flag[i] = true; label[i] = max(label[0], …, label[n-1]) + 1; while ((∃k != i) flag[k] && (label[k], k) << (label[i],i)) {} } } CS636 Swarnendu Biswas 19 Lamport’s Fast Lock • Programs with highly contended locks are likely to not scale • Insight: Ideally spin locks should be free of contention • Idea • Two lock fields x and y • Acquire: Thread t writes its id to x and y and checks for intervening writes CS636 Swarnendu Biswas 20 Lamport’s Fast Lock class LFL implements Lock { public void unlock() { private int x, y; y = ⊥; boolean[] trying; trying[ThreadID.get()] = false; } LFL() { y = ⊥; for (int i = 0; i<n; i++) { trying[i] = false; } } CS636 Swarnendu Biswas 21 Lamport’s Fast Lock public void lock() { if (x != self) { int self = ThreadID.get(); trying[self] = false; start: for (i ∈ T) { trying[self] = true; while (trying[i] == true) { x = self; // spin if (y != ⊥) { } trying[self] = false; } while (y != ⊥) {} // spin if (y != self) { goto start; while (y != ⊥) {} // spin } goto start; y = self; } } }} CS636 Swarnendu Biswas 22 Evaluation Lock Performance • Lock acquisition latency • Space overhead • Fairness • Bus traffic CS636 Swarnendu Biswas 23 Atomic Instructions in Hardware CS636 Swarnendu Biswas 24 Hardware Locks • Locks can be completely supported by hardware • Not popular on bus-based machines • Ideas: • Have a set of lock lines on the bus, processor wanting the lock asserts the line, others wait, priority circuit used for arbitrating • Special lock registers, processors wanting the lock acquired ownership of the registers • What could be some problems? CS636 Swarnendu Biswas 25 Common Atomic (RMW) Primitives test_and_set [x86, SPARC] swap [x86, SPARC] bool TAS(bool* loc): word Swap(word* a, word b): atomic { atomic { tmp := *loc; tmp := *a; *loc := true; *a := b; return tmp; return tmp; } } fetch_and_inc [uncommon] fetch_and_add [uncommon] int FAI(int* loc): int FAA(int* loc, int n): atomic { atomic { tmp := *loc; tmp := *loc; *loc := tmp+1; *loc := tmp+n; return tmp; return tmp; } } CS636 Swarnendu Biswas 26 Common Atomic (RMW) Instructions compare_and_swap [x86, IA-64, SPARC] bool CAS(word* loc, world old, word new): atomic { res := (*loc == old); if (res) *loc := new; return res; } CS636 Swarnendu Biswas 27 Common Atomic (RMW) Instructions compare_and_swap [x86, IA-64, SPARC] bool CAS(word* loc, world old, word new): atomic { res := (*loc == old); if (res) *loc := new; return res; } CS636 Swarnendu Biswas 28 Common Atomic (RMW) Instructions load_linked/store_conditional [POWER, MIPS, ARM] word LL(word* a): atomic { remember a; return *a; } bool SC(word* a, word w): atomic { res := (a is remembered, and has not been evicted since LL) if (res) *a = w; return res; } CS636 Swarnendu Biswas 29 Common Atomic (RMW) Instructions load_linked/store_conditional [POWER, MIPS, ARM] word LL(word* a): atomic { remember a; return *a; } bool SC(word* a, word w): atomic { res := (a is remembered, and has not been evicted since LL) if (res) *a = w; return res; } CS636 Swarnendu Biswas 30 ABA Problem void push(node** top, node* new): node* pop(node** top): node* old node* old, new repeat repeat old := *top old := *top new->next := old if old = null return null until CAS(top, old, new) new := old->next until CAS(top, old, new) return old top A C CS636 Swarnendu Biswas 31 ABA Problem void push(node** top, node* new): node* pop(node** top): node* old node* old, new repeat repeat old := *top old := *top new->next := old if old = null return null until CAS(top, old, new) new := old->next until CAS(top, old, new) return old top A C top A B C CS636 Swarnendu Biswas 32 ABA Problem void push(node** top, node* new): node* pop(node** top): node* old node* old, new repeattop A C repeat old := *top old := *top new->next := old if old = null return null until CAS(top, old, new) new := old->next top A B until CAS(top, Cold, new) return old top B C CS636 Swarnendu Biswas 33 Common Atomic (RMW) Instructions compare_and_swap load_linked/store_conditional • Cannot detect ABA • Guaranteed to fail • SC can experience spurious failures • E.g., Cache miss, branch misprediction CS636 Swarnendu Biswas 34 Common Atomic (RMW) Instructions load_linked/store_conditional [POWER, MIPS, ARM] word LL(word* a): atomic { remember a; return *a; } bool SC(word* a, word w): atomic { res := (a is remembered, and has not been evicted since LL) if (res) *a = w; return res; } CS636 Swarnendu Biswas 35 Centralized Mutual Exclusion Algorithms CS636 Swarnendu Biswas 36 Test-And-Set • Atomically tests and sets a word bool TAS(bool* loc) { • For example, swaps one for zero bool res; and returns the old value atomic { res = *loc; • java.util.concurrent.Atomi *loc = true; cBoolean::getAndSet(bool } val) return res; } • Bus traffic? • Fairness? CS636 Swarnendu Biswas 37 Spin Lock
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages89 Page
-
File Size-