Universality of Consensus The Art of Multiprocessor Programming Spring 2007.

Slides:



Advertisements
Similar presentations
Universality of Consensus Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
Advertisements

Lists and the Collection Interface Chapter 4. Chapter Objectives To become familiar with the List interface To understand how to write an array-based.
Mutual Exclusion – SW & HW By Oded Regev. Outline: Short review on the Bakery algorithm Short review on the Bakery algorithm Black & White Algorithm Black.
Universality of Consensus Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
1 Chapter 4 Synchronization Algorithms and Concurrent Programming Gadi Taubenfeld © 2014 Synchronization Algorithms and Concurrent Programming Synchronization.
Ch. 7 Process Synchronization (1/2) I Background F Producer - Consumer process :  Compiler, Assembler, Loader, · · · · · · F Bounded buffer.
Mutual Exclusion By Shiran Mizrahi. Critical Section class Counter { private int value = 1; //counter starts at one public Counter(int c) { //constructor.
Silberschatz, Galvin and Gagne ©2007 Operating System Concepts with Java – 7 th Edition, Nov 15, 2006 Chapter 6 (a): Synchronization.
Multiprocessor Synchronization Algorithms ( ) Lecturer: Danny Hendler The Mutual Exclusion problem.
Prof. Jennifer Welch 1. FIFO Queue Example 2  Sequential specification of a FIFO queue:  operation with invocation enq(x) and response ack  operation.
CPSC 668Set 18: Wait-Free Simulations Beyond Registers1 CPSC 668 Distributed Algorithms and Systems Fall 2006 Prof. Jennifer Welch.
Chapter 5 Queues Modified. Chapter Scope Queue processing Comparing queue implementations 5 - 2Java Software Structures, 4th Edition, Lewis/Chase.
Parallel Processing (CS526) Spring 2012(Week 6).  A parallel algorithm is a group of partitioned tasks that work with each other to solve a large problem.
The Relative Power of Synchronization Operations The Art of Multiprocessor Programming Spring 2007.
The Relative Power of Synchronization Operations Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
Introduction to Lock-free Data-structures and algorithms Micah J Best May 14/09.
Data Structures Topic #3. Today’s Agenda Ordered List ADTs –What are they –Discuss two different interpretations of an “ordered list” –Are manipulated.
1 Stack Data : a collection of homogeneous elements arranged in a sequence. Only the first element may be accessed Main Operations: Push : insert an element.
Art of Multiprocessor Programming 1 Universality of Consensus Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
1 Lock-Free Linked Lists Using Compare-and-Swap by John Valois Speaker’s Name: Talk Title: Larry Bush.
Multicore Programming
Universality of Consensus and The Nature of Progress Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
CSCE 668 DISTRIBUTED ALGORITHMS AND SYSTEMS Fall 2011 Prof. Jennifer Welch CSCE 668 Set 18: Wait-Free Simulations Beyond Registers 1.
LinkedList Many slides from Horstmann modified by Dr V.
1 Chapter 9 Synchronization Algorithms and Concurrent Programming Gadi Taubenfeld © 2014 Synchronization Algorithms and Concurrent Programming Synchronization.
Maged M.Michael Michael L.Scott Department of Computer Science Univeristy of Rochester Presented by: Jun Miao.
JAVA MEMORY MODEL AND ITS IMPLICATIONS Srikanth Seshadri
Wait-Free Consensus CPSC 661 Fall 2003 Supervised by: Lisa Higham Presented by: Wei Wei Zheng Nuha Kamaluddeen.
Common2 extended to stacks and unbound concurrency By:Yehuda Afek Eli Gafni Adam Morrison May 2007 Presentor: Dima Liahovitsky 1.
Non-Blocking Concurrent Data Objects With Abstract Concurrency By Jack Pribble Based on, “A Methodology for Implementing Highly Concurrent Data Objects,”
Wait-Free Multi-Word Compare- And-Swap using Greedy Helping and Grabbing Håkan Sundell PDPTA 2009.
Practical concurrent algorithms Mihai Letia Concurrent Algorithms 2012 Distributed Programming Laboratory Slides by Aleksandar Dragojevic.
Chapter 15 Linked Data Structures Slides prepared by Rose Williams, Binghamton University Kenrick Mock University of Alaska Anchorage Copyright © 2008.
Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects Maged M. Michael Presented by Abdulai Sei.
Software Transactional Memory Should Not Be Obstruction-Free Robert Ennals Presented by Abdulai Sei.
Concurrent Queues Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
Gal Milman Based on Chapter 10 (Concurrent Queues and the ABA Problem) in The Art of Multiprocessor Programming by Herlihy and Shavit Seminar 2 (236802)
Data Structures. Abstract Data Type A collection of related data is known as an abstract data type (ADT) Data Structure = ADT + Collection of functions.
Chapter 5 Linked List by Before you learn Linked List 3 rd level of Data Structures Intermediate Level of Understanding for C++ Please.
Distributed Algorithms (22903) Lecturer: Danny Hendler The wait-free hierarchy and the universality of consensus This presentation is based on the book.
SkipLists and Balanced Search The Art Of MultiProcessor Programming Maurice Herlihy & Nir Shavit Chapter 14 Avi Kozokin.
Graph Search II GAM 376 Robin Burke. Outline Homework #3 Graph search review DFS, BFS A* search Iterative beam search IA* search Search in turn-based.
An algorithm of Lock-free extensible hash table Yi Feng.
Concurrent Computing Seminar Introductory Lecture Instructor: Danny Hendler
Queues CS 367 – Introduction to Data Structures. Queue A queue is a data structure that stores data in such a way that the last piece of data stored,
Distributed Algorithms (22903) Lecturer: Danny Hendler Lock-free stack algorithms.
The Relative Power of Synchronization Operations Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit.
Implementing Mutual Exclusion Andy Wang Operating Systems COP 4610 / CGS 5765.
Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Concurrent Skip Lists.
LINKED LISTS.
Linked Data Structures
Distributed Algorithms (22903)
EECE 310: Software Engineering
Distributed Algorithms (22903)
Distributed Algorithms (22903)
Distributed Algorithms (22903)
Universality of Consensus
Distributed Algorithms (22903)
CSCE 668 DISTRIBUTED ALGORITHMS AND SYSTEMS
Universality of Consensus
Distributed Algorithms (22903)
Distributed Algorithms (22903)
The Relative Power of Synchronization Methods
Barrier Synchronization
Implementing Mutual Exclusion
Implementing Mutual Exclusion
Multicore programming
The Relative Power of Synchronization Operations
Nir Shavit Multiprocessor Synchronization Spring 2003
The Relative Power of Synchronization Operations
Presentation transcript:

Universality of Consensus The Art of Multiprocessor Programming Spring 2007

© Copyright Herlihy-Shavit Turing Computability A mathematical model of computation Computable = Computable on a T-Machine

© Copyright Herlihy-Shavit Shared-Memory Computability Model of asynchronous concurrent computation Computable = Wait-free/Lock-free computable on a multiprocessor cache shared memory cache

© Copyright Herlihy-Shavit The Consensus Hierarchy [Herlihy] 1 Read/Write Registers, Snapshots… 2 getAndSet, getAndIncrement, … ∞ compareAndSet,… FIFO Queue, LIFO Stack Multiple Assignment Can we implement them from any other object that has consensus number ∞? Like compareAndSet()…

© Copyright Herlihy-Shavit Theorem: Universality Consensus is universal From n-thread consensus build a –Wait-free –Linearizable –n-threaded implementation –Of any sequentially specified object

© Copyright Herlihy-Shavit Proof Outline A universal construction –From n-consensus objects –And atomic registers Any wait-free linearizable object –Not a practical construction –But we know where to start looking …

© Copyright Herlihy-Shavit Like a Turing Machine This construction –Illustrates what needs to be done –Optimization fodder Correctness, not efficiency –Why does it work? (Asks the scientist) –How does it work? (Asks the engineer) –Would you like fries with that? (Asks the liberal arts major)

© Copyright Herlihy-Shavit A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); }

© Copyright Herlihy-Shavit A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); } Push:5, Pop:null

© Copyright Herlihy-Shavit Invocation public class Invoc { public String method; public Object[] args; }

© Copyright Herlihy-Shavit Invocation public class Invoc { public String method; public Object[] args; } Method name

© Copyright Herlihy-Shavit Invocation public class Invoc { public String method; public Object[] args; } Arguments

© Copyright Herlihy-Shavit A Generic Sequential Object public interface SeqObject { public abstract Response apply(Invocation invoc); } OK, 4

© Copyright Herlihy-Shavit Response public class Response { public Object value; } Return value

© Copyright Herlihy-Shavit A Universal Concurrent Object public interface SeqObject { public abstract Response apply(Invocation invoc); } A concurrent object that is linearizable to the generic sequential object

© Copyright Herlihy-Shavit Start with Lock-Free Universal Construction First Lock-free: infinitely often some method call finishes. Then Wait-Free: each method call takes a finite number of steps to finish

© Copyright Herlihy-Shavit Universal Construction: Naïve Idea Use consensus object to store pointer to cell with current state Each thread creates new cell –computes outcome, –and tries to switch pointer to its outcome Unfortunately not… –consensus objects can be used once only

© Copyright Herlihy-Shavit Naïve Idea enq deq

© Copyright Herlihy-Shavit head Naïve Idea deq Concurrent Object enq ? Decide which to apply using consensus No good. Each thread can use consensus object only once

© Copyright Herlihy-Shavit Improved Idea: Linked-List Representation enq tail deq Each node contains a fresh consensus object used to decide on next operation

© Copyright Herlihy-Shavit Universal Construction Object represented as –Initial Object State –A Log: a linked list of the method calls New method call –Find end of list –Atomically append call –Compute response by traversing the log upto the call

© Copyright Herlihy-Shavit Basic Idea Use one-time consensus object to decide next pointer All threads update actual next pointer based on decision –OK because they all write the same value Challenges –Lock-free means we need to worry what happens if a thread stops in the middle

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Standard interface for class whose objects are totally ordered

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures the invocation

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Decide on next node (next method applied to object)

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Traversable pointer to next node (needed because you cannot repeatedly read a consensus object)

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Seq number

© Copyright Herlihy-Shavit public class Node implements java.lang.Comparable { public Invoc invoc; public Consensus decideNext; public Node next; public int seq; public Node(Invoc invoc) { invoc = invoc; decideNext = new Consensus () seq = 0; } Basic Data Structures Create a new node for a given method invocation

© Copyright Herlihy-Shavit Universal Object head 123 decideNext (Consensus Object) Ptr to cell w/highest Seq Num Seq number, Invoc tail node next 4

© Copyright Herlihy-Shavit Universal Object head 123 All threads repeatedly modify head…back to where we strated? tail node 4

© Copyright Herlihy-Shavit … The Solution head 123 tail node i 4 Make head an array Ptr to node at front Thread i updates location i Threads find head by finding Max of nodes pointed to by head array

© Copyright Herlihy-Shavit Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail }

© Copyright Herlihy-Shavit Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Head Pointers Array

© Copyright Herlihy-Shavit Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Tail is a sentinel node with sequence number 1

© Copyright Herlihy-Shavit Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Tail is a sentinel node with sequence number 1

© Copyright Herlihy-Shavit Universal Object public class Universal { private Node[] head; private Node tail = new Node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail } Initially head points to tail

© Copyright Herlihy-Shavit public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value

© Copyright Herlihy-Shavit public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Traverse the array

© Copyright Herlihy-Shavit public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Compare the seq nums of nodes pointed to by the array

© Copyright Herlihy-Shavit public static Node max(Node[] array) { Node max = array[0]; for (int i = 0; i < array.length; i++) if (max.seq < array[i].seq) max = array[i]; return max; } Find Max Head Value Compare the seq nums of nodes pointed to by the array

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } …

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Compare the seq nums of nodes pointed to by the array

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … My id

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … My method call

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … As long as I have not been threaded into list

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Node at head of list that will try and to append to

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Decide winning node; could have already been decided

© Copyright Herlihy-Shavit Universal Application public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Set next pointer based on decision Could have already been set by winner…in which case no affect

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … Set seq number indicating node was appended

© Copyright Herlihy-Shavit Universal Application Part I public Response apply(Invoc invoc) { int i = ThreadID.get(); Node prefer = new node(invoc); while (prefer.seq == 0) { Node before = Node.max(head); Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } … add to head array so new head will be found

© Copyright Herlihy-Shavit Part II – Compute Response nullenq( ) tail Red’s method call … deq() enq( ) Return Private copy of object

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); }

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Compute the result by sequentially applying the method calls in the list to a private copy of the object starting from the initial state

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Start with initialized copy of the sequential object

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } First new method call is appended after the tail

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } While not reached my own method call

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Apply the current nodes method to object

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Return the result after applying my own method call

© Copyright Herlihy-Shavit Correctness List defines linearized sequential history Thread returns its response based on list order

© Copyright Herlihy-Shavit Lock-freedom Lock-free because New winner node is added into the head array within a finite number of steps A thread moves forward in list Can repeatedly fail to win consensus on “real” head only if another succeeds

© Copyright Herlihy-Shavit Wait-free Construction Lock-free construction + announce array Stores (pointer to) node in announce –If a thread doesn’t append its node –Another thread will see it in array and help append it

© Copyright Herlihy-Shavit Helping “Announcing” my intention –Guarantees progress –Even if the scheduler hates me –My method call will complete Makes protocol wait-free Otherwise starvation possible

© Copyright Herlihy-Shavit … … Wait-free Construction head 123 tail i 4 announce Ptr to cell i wants to append i

© Copyright Herlihy-Shavit public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array

© Copyright Herlihy-Shavit public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array Announce array

© Copyright Herlihy-Shavit public class Universal { private Node[] announce; private Node[] head; private Node tail = new node(); tail.seq = 1; for (int j=0; j < n; j++){ head[j] = tail; announce[j] = tail }; The Announce Array All entries initially point to tail

© Copyright Herlihy-Shavit public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help

© Copyright Herlihy-Shavit public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Announce new method call (node), asking help from others

© Copyright Herlihy-Shavit public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Look for end of list

© Copyright Herlihy-Shavit public Response apply(Invoc invoc) { int i = ThreadID.get(); announce[i] = new Node(invoc); head[i] = Node.max(head); while (announce[i].seq == 0) { … // while node not appended to list … } A Cry For Help Main loop, while node not appended (either by me or some thread helping me)

© Copyright Herlihy-Shavit Main Loop Non-zero sequence number indicates success Thread keeps helping append nodes Until its own node is appended

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Keep trying until my cell gets a sequence number

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Possible end of list

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Main Loop Who do I help?

© Copyright Herlihy-Shavit Altruism Choose a thread to “help” If that thread needs help –Try to append its node –Otherwise append your own Worst case –Everyone tries to help same pitiful loser –Someone succeeds

© Copyright Herlihy-Shavit Help! When last node in list has sequence number k All threads check … –Whether thread k+1 mod n wants help –If so, try to append her node first

© Copyright Herlihy-Shavit Help! First time after thread k+1 announces –No guarantees After n more nodes appended –Everyone sees that thread k+1 wants help –Everyone tries to append that node –Someone succeeds

© Copyright Herlihy-Shavit Sliding Window Lemma After thread A announces its node No more than n other calls –Can start and finish –Without appending A’s node

© Copyright Herlihy-Shavit Helping head Max head +1 = N+4 N+2 N+3 … announce Thread 4: Help me! 4 So all see and help append 4 tail

© Copyright Herlihy-Shavit The Sliding Help Window head N+2 N+3 … announce 4 tail Help 3 Help 4

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Sliding Help Window In each main loop iteration pick another thread to help

© Copyright Herlihy-Shavit while (announce[i].seq == 0) { Node before = head[i]; Node help = announce[(before.seq + 1 % n)]; if (help.seq == 0) prefer = help; else prefer = announce[i]; … Sliding Help Window Help if help required, but otherwise it’s all about me!

© Copyright Herlihy-Shavit Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; }

© Copyright Herlihy-Shavit Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Decide next node to be appended

© Copyright Herlihy-Shavit Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Update next based on decision

© Copyright Herlihy-Shavit Rest is Same as Lock-free while (prefer.seq == 0) { … Node after = before.decideNext.decide(prefer); before.next = after; after.seq = before.seq + 1; head[i] = after; } Tell world that node is appended

© Copyright Herlihy-Shavit Finishing the Job Once thread’s node is linked The rest is again the same as in lock- free alg Compute the result by sequentially applying the method calls in the list to a private copy of the object starting from the initial state

© Copyright Herlihy-Shavit Then Same Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); }

© Copyright Herlihy-Shavit Universal Application Part II... //compute my response SeqObject MyObject = new SeqObject(); current = tail.next; while (current != prefer){ MyObject.apply(current.invoc); current = current.next; } return MyObject.apply(current.invoc); } Return the result after applying my own method call

© Copyright Herlihy-Shavit Shared-Memory Computability Wait-free/Lock-free computable = Threads with methods that solve n- consensus Universal Object

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean getAndSet(int update) { int prior = this.value; this.value = update; return prior; } GetAndSet is not Universal (1)

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean getAndSet(int update) { int prior = this.value; this.value = update; return prior; } GetAndSet is not Universal (1) Consensus number 2

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean getAndSet(int update) { int prior = this.value; this.value = update; return prior; } GetAndSet is not Universal (1) Not universal for ≥ 3 threads

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean compareAndSet(int expected, int update) { int prior = this.value; if (this.value == expected) { this.value = update; return true; } return false; }} CompareAndSet is Universal (1)

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean compareAndSet(int expected, int update) { int prior = this.value; if (this.value == expected) { this.value = update; return true; } return false; }} CompareAndSet is Universal (1) Consensus number ∞

© Copyright Herlihy-Shavit public class RMWRegister { private int value; public boolean compareAndSet(int expected, int update) { int prior = this.value; if (this.value == expected) { this.value = update; return true; } return false; }} CompareAndSet is Universal (1) Universal for any number of threads

© Copyright Herlihy-Shavit Practical Implications Any architecture that does not provide a universal primitive has inherent limitations You cannot avoid locking for concurrent data structures …

© Copyright Herlihy-Shavit Older Architectures IBM 360 –testAndSet (getAndSet) NYU UltraComputer –getAndAdd Neither universal –Except for 2 threads

© Copyright Herlihy-Shavit Newer Architectures Intel x86, Itanium, SPARC –compareAndSet Alpha AXP, PowerPC –Load-locked/store-conditional All universal –For any number of threads Trend is clear …