Relaxed Linear References for Lock-free Data Structures Elias Castegren , Tobias Wrigstad ECOOP’17, Barcelona sa Structured Aliasing
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
http://2.bp.blogspot.com/-ed71CELc5pY/T-h5pPLBR-I/AAAAAAAAAck/9hILp4JdDJg/s1600/annicasxperia+juni+026.jpg 3
”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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 0 1 1 1 0 15
Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 0 0 1 1 1 16
Relaxed Linear References • Separate aliasing from ownership - Unbounded aliasing, linear ownership - Ownership can be atomically transferred between aliases 1 0 1 0 1 17
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
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
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
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
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
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
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