relaxed linear references for lock free data structures
play

Relaxed Linear References for Lock-free Data Structures Elias - PowerPoint PPT Presentation

Relaxed Linear References for Lock-free Data Structures Elias Castegren , Tobias Wrigstad ECOOP17, Barcelona sa Structured Aliasing http://www.kristianstadik.se/www/wordpress/wp-content/uploads/2016/06/midsommar.jpg


  1. Relaxed Linear References for Lock-free Data Structures Elias Castegren , Tobias Wrigstad ECOOP’17, Barcelona sa Structured Aliasing

  2. http://www.kristianstadik.se/www/wordpress/wp-content/uploads/2016/06/midsommar.jpg http://www.vikstroms.nu/cms/wp-content/uploads/2014/06/Midsommar-2014.png http://pix.tagapi.aller.se/sf.php?src=http://stilexperten.mabra.com/wp-content/uploads/sites/ 2 36/2016/06/383ab62d304910ab9e9bb9a0f197d918.jpg&w=640&h=400&a=c

  3. http://2.bp.blogspot.com/-ed71CELc5pY/T-h5pPLBR-I/AAAAAAAAAck/9hILp4JdDJg/s1600/annicasxperia+juni+026.jpg 3

  4. ”Små grodorna är lustiga att se” https://upload.wikimedia.org/wikipedia/en/e/e7/The_Swedish_Chef.jpg https://68.media.tumblr.com/5cab6229774bfb3fa6a35bf3479b6f8c/ tumblr_inline_nht61yoHMA1r0y63m.jpg https://s3.amazonaws.com/gs-geo-images/ 4 3738763b-2dc4-47fb-81d2-345908ddbc07_l.jpg

  5. Lock-free Programming • Fine-grained concurrency achieved by following some protocol 1. Read a shared value (speculation) 2. Perform some local computation 3. If the speculation is still valid, make the local value global (publication) • Requires atomic operations, e.g. CAS (compare-and-swap) def CAS(x.f, y, z) : bool { } Performed atomically if (x.f == y) { x.f = z; return true; } else return false; } 5

  6. Example: A Lock-free Stack [Treiber] struct Node { struct Stack { var elem : T; var top : Node; val next : Node; } } top next N N N Stack elem T T T 6

  7. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; } } top N N N Stack T T T 7

  8. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; } } oldTop top N N N Stack T T T 7

  9. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  10. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  11. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  12. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  13. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  14. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  15. Example: A Lock-free Stack [Treiber] def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; oldTop } } oldTop top N N N Stack T T T 7

  16. Example: A Lock-free Queue [Michael & Scott] struct Node { struct Queue { var elem : T; var first : Node; var next : Node; var last : Node } } last first next Queue N N N elem T T T 8

  17. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; } } Queue N N N T T T 9

  18. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; } } n Queue N N N N T T T T 9

  19. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; } } n oldLast Queue N N N N T T T T 9

  20. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; } } n oldLast Queue N N N N T T T T 9

  21. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; oldLast } } n oldLast Queue N N N N T T T T 9

  22. Example: A Lock-free Queue [Michael & Scott] def enqueue(q : Queue, x : Elem) : void { val n = new Node(x); val done = false; while (not done) { val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; oldLast } } n oldLast Queue N N N N T T T T 9

  23. Finding Patterns in Lock-free Programming def enqueue(q : Queue, x : Elem) : void { • Speculation val n = new Node(x); val done = false; • Publication while (not done) { • Acquisition val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; def dequeue(q : Queue) : T { } ... } } def pop(s : Stack) : T { def push(s : Stack, x : T) : void { while (true) { ... val oldTop = s.top; } if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 10

  24. Finding Patterns in Lock-free Programming def enqueue(q : Queue, x : Elem) : void { • Speculation val n = new Node(x); • Publication val done = false; while (not done) { • Acquisition val oldLast = q.last; done = CAS(oldLast.next, null , n); q.last = oldLast.next; def dequeue(q : Queue) : T { } Field ’last’ is subject to races and ... } must be written to with a CAS. } def pop(s : Stack) : T { def push(s : Stack, x : T) : void { while (true) { ... Our idea: Give these concepts val oldTop = s.top; } if (CAS(s.top, oldTop, oldTop.next)) meaningful types! return oldTop.elem; } } 10

  25. Why Types? • Why not model checking, concurrent separation logic, etc.? • Modularity: no need for inter-procedural analysis • Language expressivity: allow concurrent data structures storing linear references X X X 11

  26. Why Types? • Why not model checking, concurrent separation logic, etc.? • Modularity: no need for inter-procedural analysis • Language expressivity: allow concurrent data structures storing linear references X X X 12

  27. Linear References for Ownership Transfer • A linear reference is the only reference to an object • Prohibits shared access to objects • Makes ownership explicit X 13

  28. Linear References for Ownership Transfer • A linear reference is the only reference to an object • Prohibits shared access to objects • Makes ownership explicit X • A correct lock-free data-structure can guarantee exclusive ownership of an element — Can we use linear references to capture this? 13

  29. Linear References and Lock-free Programming def pop(s : Stack) : T { Aliasing! while (true) { val oldTop = s.top; if (CAS(s.top, oldTop, oldTop.next)) return oldTop.elem; } } Sharing! Aliasing! N N N Stack T T T 14

  30. Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 0 1 1 1 0 15

  31. Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 0 0 1 1 1 16

  32. Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 1 0 1 0 1 17

  33. CAT Atomic Ownership Transfer with CAS CAT(x.f, y, z) — ”Transfer ownership of x.f to y and of z to x.f ” 1 z B2 C2 x 1 f A B1 C1 y 0 19

  34. CAT Atomic Ownership Transfer with CAS CAT(x.f, y, z) — ”Transfer ownership of x.f to y and of z to x.f ” 0 z B2 C2 1 x f A B1 C1 y 1 19

  35. Ownership Transfer in Action def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAT(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 1 1 top N N N Stack T T T 20

  36. Ownership Transfer in Action def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAT(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 1 1 top N N N Stack T T T 20

  37. Ownership Transfer in Action def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAT(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 1 1 top N N N Stack T T T 20

  38. Ownership Transfer in Action def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAT(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 1 1 top N N N Stack T T T 20

  39. Ownership Transfer in Action def pop(s : Stack) : T { while (true) { val oldTop = s.top; if (CAT(s.top, oldTop, oldTop.next)) return oldTop.elem; } } 1 1 top N N N Stack T T T 20

Recommend


More recommend