keep off the grass
play

Keep Off the Grass Locking the Right Path for Atomicity Dave - PowerPoint PPT Presentation

Keep Off the Grass Locking the Right Path for Atomicity Dave Cunningham Khilan Gudka Susan Eisenbach Imperial College London CC 2008 1/25 Atomic blocks Example: atomic { Node x = new Node(); x.next = list.first; list.first = x; }


  1. Keep Off the Grass Locking the Right Path for Atomicity Dave Cunningham Khilan Gudka Susan Eisenbach Imperial College London CC 2008 1/25

  2. Atomic blocks Example: atomic { Node x = new Node(); x.next = list.first; list.first = x; } • Semantics easy for programmers to understand • Guaranteed that threads don’t interfere • Concurrency much easier • Naive implementation is inefficient • Lots of research tries to interleave more threads (which is hard) 2/25

  3. Two ways of safely interleaving more threads Transactional Lock Memory Inference IO Hard Easy Reflection Easy Need JIT support Native calls Hard Hard Compiler machinery Some Lots Runtime machinery Lots Some Contention performance Slow Fast Granularity Perfect Reasonable Key: good, OK, bad 3/25

  4. Two-phase lock Discipline • Everyone uses two-phase discipline • Known that two-phase discipline ⇒ atomicity (Eswaran et al, ’76) • Constraints: • Lock acquisitions precede lock releases • All accesses nested within appropriate locks Example: ... 4 (´ 2 2 4 ´ 1 1 4 ´ 3 ` 1 2 2 4 ` 2 3 ` 3) 4 ... 4/25

  5. Example 1 - Single Access Source Target atomic { lock(this); x = this.f x = this.f; } unlock(this); 5/25

  6. Example 1 - Single Access Source Target atomic { // if f is final x = this.f // or this is thread-local } x = this.f; 5/25

  7. Example 1 - Single Access Source Target atomic { // if f is final x = this.f // or this is thread-local } x = this.f; Henceforth, everything is non-final and shared between threads. 5/25

  8. Example 2 - Two accesses Source Target lock(this); atomic { this.f = 42; this.f = 42; lock(x); x.f = 20; unlock(this); } x.f = 20; unlock(x); 6/25

  9. Example 2 - Two accesses Source Target while (true) { atomic { lock(this); this.f = 42; if (lock(x)) { x.f = 20; break; // yes, proceed } } else { unlock(this); } // no, try again } this.f = 42; unlock(this); x.f = 20; unlock(x); 6/25

  10. Example 2 - Two accesses Source Target while (true) { atomic { lock(this); this.f = 42; if (lock(x)) { // what if x==null? x.f = 20; break; // yes, proceed } } else { unlock(this); } // no, try again } this.f = 42; unlock(this); x.f = 20; unlock(x); 6/25

  11. Example 2 - Two accesses Source Target while (true) { atomic { lock(this); this.f = 42; if (x==null || lock(x)) { x.f = 20; break; // yes, proceed } } else { unlock(this); } // no, try again } this.f = 42; unlock(this); x.f = 20; unlock(x); 6/25

  12. Example 2 - Two accesses Source Target // from now on, assume: atomic { // - deadlock free this.f = 42; // - NPE free x.f = 20; lock(this,x); } this.f = 42; unlock(this); x.f = 20; unlock(x); 6/25

  13. Pause For Thought on Deadlock... • We cannot insert locks that may deadlock • Related work avoids deadlock by using ordering locks statically... • ... but this seriously hurts granularity • Our rollback strategy should have better granularity • All lock acquisitions moved to top, this might hurt granularity a bit • No transaction log required • In our experience, rollback is actually very rare (minimal overhead) 7/25

  14. Example 3 - Assign Source Target atomic { lock(x); x = this; x = this; x.f = 42; x.f = 42; } unlock(x); 8/25

  15. Example 3 - Assign Source Target atomic { lock(this); x = this; x = this; x.f = 42; x.f = 42; } unlock(x); 8/25

  16. Example 4 - Load Source Target lock(this,this.g); atomic { x = this.g x = this.g; unlock(this); x.f = 42; x.f = 42; } unlock(x); 9/25

  17. Example 5 - Store Source Target lock(x,this); atomic { x.g = this; x.g = this; y = x.g; y = x.g; unlock(x); y.f = 42; y.f = 42; } unlock(y); 10/25

  18. Example 6 - Construction Source Target atomic { x = new C; x = new C; x.f = 42; x.f = 42; } atomic { x = null; x = null; x.f = 42; x.f = 42; } 11/25

  19. Example 7 - Readers/Writers Many threads may read concurrently. Source Target lockw(x); atomic { x.f = 10; x.f = 10; lockr(x); y = x.g; unlockw(x); } y = x.g; unlockr(x); 12/25

  20. How Does This Work? Source CFG Target // "Store" example // again. atomic { x.g = this; y = x.g; y.f = 42; } // This time // we will use // r/w locks. 13/25

  21. How Does This Work? Source CFG Target // "Store" example // again. atomic { x.g = this; y = x.g; y.f = 42; } // This time // we will use // r/w locks. 13/25

  22. How Does This Work? Source CFG Target // "Store" example // again. atomic { x.g = this; y = x.g; y.f = 42; } // This time // we will use // r/w locks. 13/25

  23. How Does This Work? Source CFG Target // "Store" example // again. atomic { x.g = this; y = x.g; y.f = 42; } // This time // we will use // r/w locks. 13/25

  24. How Does This Work? Source CFG Target lockw(x,this); // "Store" example x.g = this; // again. lockr(x); unlockw(x); atomic { //lockw(x.g); x.g = this; //unlockw(this); y = x.g; y.f = 42; y = x.g; } //lockw(y); //unlockw(x.g); // This time unlockr(x); // we will use // r/w locks. y.f = 42; unlockw(y); 13/25

  25. Example8 - If Source Target atomic { if (b) { veh = bus; } else { veh = car; } veh.fuel = 42; } 14/25

  26. Example8 - If Source Target atomic { if (b) { veh = bus; } else { veh = car; } veh.fuel = 42; } 14/25

  27. Example8 - If Source Target atomic { if (b) { veh = bus; } else { veh = car; } veh.fuel = 42; } 14/25

  28. Example8 - If Source Target atomic { if (b) { veh = bus; } else { veh = car; } veh.fuel = 42; } 14/25

  29. Example8 - If Source Target lockw(car,bus); atomic { if (b) { if (b) { unlockw(car); veh = bus; veh = bus; } else { } else { veh = car; unlockw(bus); } veh = car; veh.fuel = 42; } } veh.fuel = 42; unlockw(veh); 14/25

  30. Example 9 - While class Node { Node n; int f; } //lockw(x, x.n, x.n.n, ...); atomic { while (x.n!=null) { while (x.n!=null) { x = x.n; x = x.n; } } x.f = 42; x.f = 42; } 15/25

  31. Example 9 - While class Node { Node n; int f; } lockw(Node); atomic { while (x.n!=null) { while (x.n!=null) { x = x.n; x = x.n; } } lockw(x); x.f = 42; unlockw(Node); } x.f = 42; unlockw(x); 15/25

  32. How does it work? atomic { while (...) { x = x.n; } } 16/25

  33. How does it work? atomic { while (...) { x = x.n; } } 16/25

  34. How does it work? atomic { while (...) { x = x.n; } } 16/25

  35. How does it work? atomic { while (...) { x = x.n; } } 16/25

  36. How does it work? atomic { while (...) { x = x.n; } } 16/25

  37. How does it work? atomic { while (...) { x = x.n; } } 16/25

  38. How does it work? atomic { while (...) { x = x.n; } } 16/25

  39. How does it work? atomic { while (...) { x = x.n; } } 16/25

  40. How does it work? atomic { while (...) { x = x.n; } } Analysis doesn’t terminate :( 16/25

  41. How does it work? atomic { while (...) { x = x.n; } } How do we solve this? 16/25

  42. How does it work? atomic { while (...) { x = x.n; } } First, number the CFG nodes... 16/25

  43. How does it work? atomic { while (...) { x = x.n; } } First, number the CFG nodes... 16/25

  44. Nondeterministic Finite Automata Recap: • Propogating sets of “paths” through the graph. • (This is a static characterisation of a set of objects.) • We cannot represent an infinite set of paths: { x , x . n , x . n . n , . . . } • Use regular expressions? { x . n ∗ } (sadly, hard to mechanise...) • Use nondeterministic finite automata (NFAs)? NFAs easily represent infinite sets of paths! Represent with a set of edges: { x �→ 1 , 1 → n 1 } Constrain the set of automata nodes to the set of CFG nodes... 17/25

  45. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } 18/25

  46. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } 18/25

  47. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } 18/25

  48. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } 18/25

  49. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } 18/25

  50. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } Analysis now terminates. 18/25

  51. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } Analysis now terminates. How do we insert locks? 18/25

  52. How does it work? NFAs avoid the infinite loop: atomic { while (...) { x = x.n; } } Analysis now terminates. How do we insert locks? 18/25

  53. How does it work? NFAs avoid the infinite loop: atomic { lockr(Node); while (...) { while (...) { x = x.n; x = x.n; } } } unlockr(Node); Analysis now terminates. How do we insert locks? 18/25

  54. The Transfer Functions Program analyses defined by transfer functions f ( st n ) Addition function a ( st n ) inserts the accesses performed by st Translation function t ( st n )( G ) rewrites G to compensate for state change 19/25

  55. Addition function (introduces new accesses into the CFG) 20/25

Recommend


More recommend