TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: A A A AAA A A A AA A Proving that non-blocking algorithms don't block Alexey Gotsman University of Cambridge Joint work with Byron Cook, Matthew Parkinson, and Viktor Vafeiadis
Proving that non-blocking algorithms don't block Automatically proving liveness properties of non- blocking concurrent algorithms Stay awake: nice links between programming, logic, and automatic verification Pick a class of programs Pick an appropriate logic Observe that proofs are simple and follow the same pattern Infer proofs automatically Best of both worlds: automatic tool + understanding of the algorithms
Coarse-grained locking Top Inefficient as only one thread operates on the list at a time NULL
Non-blocking concurrency Multiple threads operating on the data structure at the same time Typical programming idiom:... L:read from a part of the data structure do some work on the results try to change the data structure if interference is detected go to L...
Non-blocking concurrency Stacks, queues, skip lists, hash tables, etc. Used in practice: e.g., java.util.concurrent Complicated and hard to get right Formal verification: Safety properties [Yahav , Calcagno , Amit , Manevich , Vafeiadis 2009] Termination ?
Non-blocking concurrency: Treiber's stack Top NULL void push(data_t v) { Node *t, *x; x = new Node(); x->val = v; do { t = Top; x->next = t; } while(!CAS(&Top,t,x)); } data_t pop() { Node *t, *x; do { t = Top; if (t == NULL) return EMPTY; x = t->next; } while(!CAS(&Top,t,x)); return t->val; } struct Node { Node *next; data_t val; } *Top;
Treiber's non-blocking stack: termination void push(data_t v) { Node *t, *x; x = new Node(); x->val = v; do { t = Top; x->next = t; } while(!CAS(&Top,t,x)); } data_t pop() { Node *t, *x; do { t = Top; if (t == NULL) return EMPTY; x = t->next; } while(!CAS(&Top,t,x)); return t->val; } struct Node { Node *next; data_t val; } *Top; push or pop may not terminate if other threads continually modify Top However: some operation will always terminate This talk: logic & tool for proving lock-freedom lock-freedom
From lock-freedom to termination
Lock-freedom of Treiber's stack Push or Id Shared state Rely/guarantee + separation logic for safety [Vafeiadis-Parkinson 2007] void push(data_t v) { Node *t, *x; x = new Node(); x->val = v; do { t = Top; x->next = t; } while(!CAS(&Top,t,x)); } data_t pop() { Node *t, *x; do { t = Top; if (t == NULL) return EMPTY; x = t->next; } while(!CAS(&Top,t,x)); return t->val; } struct Node { Node *next; data_t val; } *Top; Pop or Id
Lock-freedom of Treiber's stack Push or Id void push(data_t v) { Node *t, *x; x = new Node(); x->val = v; do { t = Top; x->next = t; } while(!CAS(&Top,t,x)); } data_t pop() { Node *t, *x; do { t = Top; if (t == NULL) return EMPTY; x = t->next; } while(!CAS(&Top,t,x)); return t->val; } struct Node { Node *next; data_t val; } *Top; Pop or Id
Lock-freedom of Treiber's stack The do loops terminate if no-one else executes Push or Pop infinitely often No-one executes Push or Pop infinitely often Hence, push and pop terminate Push or Id data_t pop() { Node *t, *x; do { t = Top; if (t == NULL) return EMPTY; x = t->next; } while(!CAS(&Top,t,x)); return t->val; } void push(data_t v) { Node *t, *x; x = new Node(); x->val = v; do { t = Top; x->next = t; } while(!CAS(&Top,t,x)); } struct Node { Node *next; data_t val; } *Top; Pop or Id
Layered proof “I execute only Push, Pop, or Id” “I don’t execute Push or Pop infinitely often” “I terminate” “I execute only Push, Pop, or Id”
Layered proof Formalised in a logic for liveness and heaps Guarantees of the form
Run the safety checker: Iteratively eliminate actions: Proof search strategy Proof valid for an arbitrary number of threads
Case studies Treiber's stack [Treiber 1986] HSY stack [Hendler ] Non-blocking queue [Michael, Scott 1996] Linked list [Michael 2002] RDCSS [Harris ]
Conclusion Automatic method with proofs reflecting algorithm structure Hope the general approach can be reused Lock-based lock-free algorithms require more complex environment assumptions