Distributed Algorithms 22903 Lockfree stack algorithms Lecturer Danny
Distributed Algorithms (22903) Lock-free stack algorithms Lecturer: Danny Hendler
2
Concurrent Objects • Each object has a state – Usually given by a set of shared memory fields • Objects may be implemented from simpler base objects • Each object supports a set of operations – Only way to manipulate state – E. g. – a shared counter supports the fetch&increment operation 3
Shared Objects Correctness of a sequential counter • fetch&increment, applied to a counter with value v, returns v and increments the counter’s value to (v+1). • Values returned by consecutive operations: 0, 1, 2, … But how shall we define the correctness of a shared counter? 4
Shared Objects Correctness (cont’d) fetch&inc q. enq(x) Invocation Response q. deq(y) fetch&inc q. enq(y) fetch&inc q. deq(x) fetch&inc time There is only a partial order between operations! 5
Shared Objects Correctness (cont’d) A sequential object history is a sequence of matching invocations and responses on the object. Example: a sequential history of a FIFO queue q. enq(3) q: void q. enq(7) q: void q. deq() q: 3 q. deq() q: 7 6
Sequential specification The correct behavior of the object in the absence of concurrency: a set of legal sequential object histories. Example: the sequential spec of a counter H 0 : H 1 : H 2 : H 3 : H 4 : . . . c. f&i() c: 0 c. f&i() c: 1 c. f&i() c: 2 c. f&i() c: 3 7
Shared Objects Correctness (cont’d) Linearizability An execution is linearizable if there exists a permutation of the operations on each object o, , such that: • is a sequential history of o • preserves the partial order of the execution. 8
Example lin ea q. enq(x) q. enq(y) q. deq(y) riz ab le q. deq(x) time 9
Example no t q. enq(x) q. deq(y) lin ea riz ab le q. enq(y) time 10
Wait-freedom vs. lock-freedom • Wait-freedom – each process completes its operation on the in a finite number of its own steps • Lock-freedom – some process completes its operation on the object after a finite number of steps is taken 11
The compare&swap operation Comare&swap(b, old, new) atomically v read from b if (v = old) { b new return success } else return failure; Motorola 680 x 0 IBM 370 Sun SPARC 80 X 86 MIPS Power. PC DECAlpha 12
Treiber’s stack algorithm Top val next … val next Push(int v, Stack S) 1. n : = new NODE ; create node for new stack item 2. n. val : = v ; write item value 3. do forever ; repeat until success 4. node top : = S. top 5. n. next : = top ; next points to current (LIFO order) 6. if compare&swap(S, top, n) ; try to add new item 7. return ; return if succeeded 8. od 13
Treiber’s stack algorithm (cont’d) Top val next … val next Pop(Stack S) 1. do forever 2. top : = S. top 3. if top = null 4. return empty 5. if compare&swap(S, top. next) 6. return top. val 7. od 14
Treiber’s stack algorithm (cont’d) It is easily seen that the alg is linearizable and lock-free A disadvantage of the algorithms is that… It has a sequential bottleneck. 15
An elimination backoff stack algorithm (Hendler, Shavit and Yerushalmi, 2004) Key idea: pairs of push/pop operations may collide and eliminate each other without accessing a central stack. Central stack Top val next collision array … val next
Collision scenarios push pop push Collision array Central stack Top val next … val next 17
Elimination: challenges • Prevent elimination chains: e. g. , A collides with B, which collides with C… • Prevent race conditions: e. g. , A collides with B, which is already gone… push pop push Collision array Top val next Central stack val next … val next 18
Data structures Each stack operation is represented by a Thread. Info structure struct Thread. Info { id ; the identifier of the thread performing the operation op ; a PUSH/POP opcode cell ; a cell structure spin ; duration to spin } Struct Cell { ; a representation of stack item as in Treiber pnext ; pointer to the next cell pdata ; stack item } p 1 Thread Info p 2 p 3 p 4 Thread Info Location array collision array p 1 p 7 pn
Elimination-backoff stack code void Stack. Op(Thread. Info* p) { 1. if (Try. Perform. Stack. OP(p) == FALSE) ; if operation not applied to central stack 2. Les. Op(p) ; try to eliminate operation by colliding with an opposite-type operation 3. return void Les. OP(Thread. Info * p) 1. while (1) 2. location[mypid]=p ; announce arrival 3. pos=Get. Position(p) ; get a random position at the collision array 4. him=collision[pos] ; read current value of that position 5. while (!compare&swap(&collision[pos], him, mypid); try to write own ID 6. him=collision[pos] ; continue till success 7. if (him != empty) ; if read an ID of another thread 8. q=location[him] ; read a pointer to the other thread’s info 9. if (q!=NULL && q->id=him && q->op != p->op) ; if may collide 10. if (compare&swap(&location[mypid], p, NULL) ; try to prevent unwanted collisions 11. if (Try. Collision(p, q)==true) ; if collided successfully 12. return ; return code is already at Thread. Info structure 13. else goto stack ; try to apply operation to central stack 14. else Finish. Collision(p), return ; extract information and finish 15. delay (p->spin) ; Wait for other thread to collide with me 16. if (!compare&swap(&location[mypid], p, NULL) ; if someone collided with me 17. Finish. Collision(p), return; Extract information and finish 20 stack: if (Try. Perform. Stack. Op(p)==TRUE) return ; try to apply operation to central stack
Elimination-backoff stack code (cont’d) void Try. Collision(Thread. Info* p, Thread. Info *q) 1. if (p->op==PUSH) 2. if (compare&swap(&location[him], q, p)) ; give my record to other thread 3. return TRUE 4. else 5. return FALSE 6. else 7. if (compare&swap(&location[him], q, NULL)) 8. p->cell=q->cell ; get pointer to PUSH operation’s cell 9. location[mypid]=NULL; 10. return TRUE 11. else 12. return FALSE I will not have time to go over this code… void Finish. Collision(Thread. Info* p) 1. if (p->op==POP) 2. p->pcell=location[mypid]->pcell 3. location[mypid]=NULL 21
- Slides: 21