SlideShare una empresa de Scribd logo
1 de 55
ABA Problem

Dr. C.V. Suresh Babu
Introduction
• Queues are everywhere in parallel applications
and operating systems
• Many researchers have proposed queues
–
–
–
–

Hwang and Briggs
Gottlieb
Massalin
Et al. etc…

• Queue performance can be critical to operating
system performance
– Scheduling Queues
– Free memory lists
– Many other critical kernel operations
Concurrent FIFO Queue algorithms
• Blocking algorithms risk performance
degradation
– A process can be delayed or halted at inopportune
moments
• Scheduling preemption
• Page faults
• Cache misses

– Slow processes can prevent faster ones from
completing indefinitely

• Non-Blocking algorithms must solve the ABA
problem
– During contention, some process will complete
within a given number of operations
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop
value = SM
newVal = value +1
Stack Data = d
CAS(&SM, value, newVal)
break

Stack

SM
5

…
x

time

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM
newVal = value +1
Stack Data = d
CAS(&SM, value, newVal)
break

Stack

SM
4

…
x

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d
CAS(&SM, value, newVal)
break

Stack

SM
4

…
x

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1

Push(z)

Stack Data = d
CAS(&SM, value, newVal)
break

Stack

SM
4

…
x

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

Stack

SM
4

…
x

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

newVal=5

Stack

SM
4

…
x

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {
loop

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X
CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

newVal=5

Stack

CAS(&SM,value,newVal)

SM
5

…
z

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X

loop

CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

newVal=5

Stack

CAS(&SM,value,newVal)
CAS(&SM,value,newVal)

SM
5

…
z

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X

loop

CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

newVal=5

Stack

CAS(&SM,value,newVal)
CAS(&SM,value,newVal)
v1=x

SM
4

…
z

time
ABA problem

Pop () {
loop
value = SM
newVal = value -1

THREAD1

THREAD2

data = Stack Data
CAS(&SM, value, newVal)

v1=Pop()
value = 5

Push (d) {

newVal = 4

data=X

return data

value = 5

newVal = 4

break

v2=Pop()

data=X

loop

CAS(&SM,value,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

CAS(&SM, value, newVal)

value = 4

break

newVal=5

Stack

CAS(&SM,value,newVal)
CAS(&SM,value,newVal)
v1=x

SM
4

…
z

CAS should fail but it succeeds
time

Thread1 has Thread2’s data
Solutions for ABA problem
Cache Kernel
• Add version # to data structures
• Increment # during every CAS instruction
LL/SC
• Fail if Cache Line has been written to
Solution for ABA problem

Pop () {
loop
value = SM

newVal = value -1

THREAD1

THREAD2

data = Stack Data
DCAS(&SM, value,

v1=Pop()
value = 5

return data
Push (d) {

newVal = 4

data=X

break

value = 5

newVal = 4

<ver++,newVal>)

v2=Pop()

data=X

loop

DCAS(&SM,value,ver,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

DCAS(&SM, value,

value = 4

<ver++,newVal>)

newVal=5

Stack

break

DCAS(&SM,value,ver,newVal)
DCAS(&SM,value,ver,newVal)
Will not incorrectly succeed

SM
5

…
z

(ver != ver+2)

time
Solution for ABA problem

Pop () {
loop
value = SM

newVal = value -1

THREAD1

THREAD2

data = Stack Data
DCAS(&SM, value,

v1=Pop()
value = 5

return data
Push (d) {

newVal = 4

data=Z

break

value = 5

newVal = 4

<ver++,newVal>)

v2=Pop()

data=X

loop

DCAS(&SM,value,ver,newVal)

value = SM

v2 = x

newVal = value +1
Stack Data = d

Push(z)

DCAS(&SM, value,

value = 4

<ver++,newVal>)

newVal=5

Stack

break

DCAS(&SM,value,ver,newVal)
DCAS(&SM,value,ver,newVal)
Will not incorrectly succeed

SM
4

(ver != ver+2)

…
time

V1 = Z
Correctness Properties
1.
2.
3.
4.
5.

The linked list is always connected
Nodes only inserted after the last node
Nodes only deleted from beginning
Head always points to the first node
Tail always points to a node in the list
Queue # 1
• Non-Blocking Concurrent Queue
– enqueue()
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
node–>next.ptr = NULL
loop
tail = Q–>Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

“enqueue(myQueue, D1)”
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]

tail

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]

tail

next

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]

tail

next

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS( &tail.ptr–>next, next,
<node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1
[NULL]

tail

next

[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1

+1
[NULL]

tail

next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1

+1
[NULL]

tail

next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

enqueue(myQueue, D1)
enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
+1
if tail == Q–>Tail
if next.ptr == NULL
if CAS(&tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
endif
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
endif
endif
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

D1

+1
[NULL]
Concurrent enqueues
• Suppose two processes call enqueue() at
the same time
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS( &tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
Process 1
endif
Enqueue(myQueue, ABC)
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
ABC
endif
endif
[NULL]
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

tail

next

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

D1
[NULL]

Process 2
Enqueue(myQueue, XYZ)

XYZ
[NULL]

tail

next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS( &tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
Process 1
endif
Enqueue(myQueue, ABC)
else
CAS(&Q–>Tail, tail, <next.ptr,
tail.count+1>)
ABC
endif
endif
[NULL]
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

tail

next

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

D1

+1
XYZ
[NULL]

Process 2
Enqueue(myQueue, XYZ)

tail
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

enqueue(Q: pointer to queue t, value: data type)
node = new node()
node–>value = value
Head
node–>next.ptr = NULL
loop
tail = Q–>Tail
Tail
next = tail.ptr–>next
if tail == Q–>Tail
if next.ptr == NULL
if CAS( &tail.ptr–>next,
next, <node, next.count+1>)
myQueue
break
Process 1
endif
Enqueue(myQueue, ABC)
else
CAS( &Q–>Tail, tail,
<next.ptr, tail.count+1>)
ABC
endif
endif
[NULL]
endloop
CAS(&Q–>Tail, tail, <node, tail.count+1>)

tail

next

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

D1

+1
XYZ
[NULL]

Process 2
Enqueue(myQueue, XYZ)

tail
Queue #1 (cont.)
• Non-Blocking Concurrent Queue
– dequeue()
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

“dequeue(myQueue, pvalue)”

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head,
head, <next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head,
head, <next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head,
head, <next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head,
head, <next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head, head,
<next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
+1
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head, head,
<next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
+1
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head, head,
<next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
+1
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head, head,
<next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]

head

tail
next
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node

dequeue(myQueue, pvalue)

dequeue(Q: ptr to queue t, pvalue: ptr to data
type):bool
loop
Head
head = Q–>Head
+1
tail = Q–>Tail
next = head–>next
if head == Q–>Head
Tail
if head.ptr == tail.ptr
if next.ptr == NULL
return FALSE
endif
myQueue
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head, head,
<next.ptr, head.count+1>)
break
endif
endif
endif
endloop
free(head.ptr)

D1
[NULL]
Concurrent dequeues
• Suppose two processes call dequeue() at
the same time
struct pointer_t {
node_t * ptr
uint count
}

struct node_t {
data_type value
pointer_t next
}

struct queue_t {
pointer_t Head
pointer_t Tail
}

dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool
loop
head = Q–>Head
Head
tail = Q–>Tail
next = head–>next
if head == Q–>Head
if head.ptr == tail.ptr
Tail
if next.ptr == NULL
return FALSE
endif
CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>)
else
# Read value before CAS, otherwise another
# dequeue might free the next node
*pvalue = next.ptr–>value
if CAS ( &Q–>Head,head, <next.ptr, head.count+1>)
break
endif
“dequeue(myQueue,
endif
endif
endloop
free(head.ptr)
return TRUE

D1
[NULL]

pvalue)”
Queue #2
• Two-lock Concurrent Queue
struct node_t {
data_type value
node_t * next
}

struct queue_t {
pointer_t Head
pointer_t Tail
lock_type H_lock
lock_type T_lock
}

initialize(Q: pointer to queue t)
node = new node()
node–>next.ptr = NULL
Q–>Head = Q–>Tail = node
Q–>H lock = Q–>T lock = FREE

dequeue(Q: pointer to queue t, pvalue: pointer to data type): boolean
lock(&Q–>H lock)
node = Q–>Head
new head = node–>next
if new head == NULL
enqueue(Q: pointer to queue t, value: data type)
unlock(&Q–>H lock)
node = new node()
return FALSE
node–>value = value
endif
node–>next.ptr = NULL
*pvalue = new head–>value
lock(&Q–>T lock)
Q–>Head = new head
Q–>Tail–>next = node
unlock(&Q–>H lock)
Q–>Tail = node
free(node)
unlock(&Q–>T lock)
return TRUE

• Algorithms have same general structure only different
data types
• No loops, ‘busy waiting’ instead
• Only dequeues access Head Lock
• Only enqueues access Tail Lock
Performance Parameters
• Net execution time for one million
enqueue/dequeue pairs
• 12-processor Silicon Graphics Challenge
multiprocessor
• Algorithms compiled with using highest
optimization level
• Including many hand optimizations
Dedicated multiprocessor

Multiprogrammed system with 3
processes per processor

Multiprogrammed system with 2
processes per processor
Conclusion
• NBS clear winner for multiprocessor
multiprogrammed systems
• Above 5 processors, use the new nonblocking queue
• If hardware only supports test-and-set use
two lock queue
• For two or less processors use a single
lock algorithm for queues

Más contenido relacionado

La actualidad más candente

MongoDB Shell Tips & Tricks
MongoDB Shell Tips & TricksMongoDB Shell Tips & Tricks
MongoDB Shell Tips & Tricks
MongoDB
 
Cyber Threat Hunting Training (CCTHP)
Cyber Threat Hunting Training (CCTHP)Cyber Threat Hunting Training (CCTHP)
Cyber Threat Hunting Training (CCTHP)
ENOInstitute
 
Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming
Cloudflare
 
Event Sourcing with Kotlin, who needs frameworks!
Event Sourcing with Kotlin, who needs frameworks!Event Sourcing with Kotlin, who needs frameworks!
Event Sourcing with Kotlin, who needs frameworks!
Nico Krijnen
 
Dfs presentation
Dfs presentationDfs presentation
Dfs presentation
Alizay Khan
 

La actualidad más candente (20)

[JS EXPERIENCE 2018] Javascript Event Loop além do setInterval - Derek Stavis
[JS EXPERIENCE 2018] Javascript Event Loop além do setInterval - Derek Stavis[JS EXPERIENCE 2018] Javascript Event Loop além do setInterval - Derek Stavis
[JS EXPERIENCE 2018] Javascript Event Loop além do setInterval - Derek Stavis
 
Apprentissage par renforcement
Apprentissage par renforcement Apprentissage par renforcement
Apprentissage par renforcement
 
MongoDB Shell Tips & Tricks
MongoDB Shell Tips & TricksMongoDB Shell Tips & Tricks
MongoDB Shell Tips & Tricks
 
Tail recursion
Tail recursionTail recursion
Tail recursion
 
EENA 2021: Keynote – Open-Source Intelligence (OSINT) for emergency services ...
EENA 2021: Keynote – Open-Source Intelligence (OSINT) for emergency services ...EENA 2021: Keynote – Open-Source Intelligence (OSINT) for emergency services ...
EENA 2021: Keynote – Open-Source Intelligence (OSINT) for emergency services ...
 
Communication and Conflict Resolution
Communication and Conflict ResolutionCommunication and Conflict Resolution
Communication and Conflict Resolution
 
Cyber Threat Hunting Training (CCTHP)
Cyber Threat Hunting Training (CCTHP)Cyber Threat Hunting Training (CCTHP)
Cyber Threat Hunting Training (CCTHP)
 
Fidelis Endpoint® - Live Demonstration
Fidelis Endpoint® - Live Demonstration  Fidelis Endpoint® - Live Demonstration
Fidelis Endpoint® - Live Demonstration
 
Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming Go Profiling - John Graham-Cumming
Go Profiling - John Graham-Cumming
 
Detecting WMI Exploitation v1.1
Detecting WMI Exploitation v1.1Detecting WMI Exploitation v1.1
Detecting WMI Exploitation v1.1
 
Fundamentals of the Analysis of Algorithm Efficiency
Fundamentals of the Analysis of Algorithm EfficiencyFundamentals of the Analysis of Algorithm Efficiency
Fundamentals of the Analysis of Algorithm Efficiency
 
Vi Cheat Sheet v 1 00
Vi Cheat Sheet v 1 00Vi Cheat Sheet v 1 00
Vi Cheat Sheet v 1 00
 
Lecture 25 hill climbing
Lecture 25 hill climbingLecture 25 hill climbing
Lecture 25 hill climbing
 
Parallel sorting algorithm
Parallel sorting algorithmParallel sorting algorithm
Parallel sorting algorithm
 
Event Sourcing with Kotlin, who needs frameworks!
Event Sourcing with Kotlin, who needs frameworks!Event Sourcing with Kotlin, who needs frameworks!
Event Sourcing with Kotlin, who needs frameworks!
 
Fuzzing.pptx
Fuzzing.pptxFuzzing.pptx
Fuzzing.pptx
 
[논문리뷰] 딥러닝 적용한 EEG 연구 소개
[논문리뷰] 딥러닝 적용한 EEG 연구 소개[논문리뷰] 딥러닝 적용한 EEG 연구 소개
[논문리뷰] 딥러닝 적용한 EEG 연구 소개
 
Dfs presentation
Dfs presentationDfs presentation
Dfs presentation
 
Sviluppare agenti conversazionali con Rasa
Sviluppare agenti conversazionali con RasaSviluppare agenti conversazionali con Rasa
Sviluppare agenti conversazionali con Rasa
 
Bsides Chicago2017
Bsides Chicago2017Bsides Chicago2017
Bsides Chicago2017
 

Similar a ABA Problem

(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
Tomasz Wrobel
 
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm E
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm EData Structures and Algorithm AnalysisSpring 2020 Post Midterm E
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm E
jeniihykdevara
 

Similar a ABA Problem (20)

Rewriting Java In Scala
Rewriting Java In ScalaRewriting Java In Scala
Rewriting Java In Scala
 
Queue Data Structure (w/ php egs)
Queue Data Structure (w/ php egs)Queue Data Structure (w/ php egs)
Queue Data Structure (w/ php egs)
 
A bit about Scala
A bit about ScalaA bit about Scala
A bit about Scala
 
Monadologie
MonadologieMonadologie
Monadologie
 
An Introduction to Higher Order Functions in Spark SQL with Herman van Hovell
An Introduction to Higher Order Functions in Spark SQL with Herman van HovellAn Introduction to Higher Order Functions in Spark SQL with Herman van Hovell
An Introduction to Higher Order Functions in Spark SQL with Herman van Hovell
 
Michal Malohlava presents: Open Source H2O and Scala
Michal Malohlava presents: Open Source H2O and Scala Michal Malohlava presents: Open Source H2O and Scala
Michal Malohlava presents: Open Source H2O and Scala
 
Crystal Ball Event Prediction and Log Analysis with Hadoop MapReduce and Spark
Crystal Ball Event Prediction and Log Analysis with Hadoop MapReduce and SparkCrystal Ball Event Prediction and Log Analysis with Hadoop MapReduce and Spark
Crystal Ball Event Prediction and Log Analysis with Hadoop MapReduce and Spark
 
Spark workshop
Spark workshopSpark workshop
Spark workshop
 
Introduction to Machine Learning
Introduction to Machine LearningIntroduction to Machine Learning
Introduction to Machine Learning
 
Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tour
 
Perl6 a whistle stop tour
Perl6 a whistle stop tourPerl6 a whistle stop tour
Perl6 a whistle stop tour
 
flows.ppt
flows.pptflows.ppt
flows.ppt
 
(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?(How) can we benefit from adopting scala?
(How) can we benefit from adopting scala?
 
Scala
ScalaScala
Scala
 
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm E
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm EData Structures and Algorithm AnalysisSpring 2020 Post Midterm E
Data Structures and Algorithm AnalysisSpring 2020 Post Midterm E
 
Scala training workshop 02
Scala training workshop 02Scala training workshop 02
Scala training workshop 02
 
GeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheetGeoGebra JavaScript CheatSheet
GeoGebra JavaScript CheatSheet
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Java/Scala Lab: Slava Schmidt - Introduction to Reactive StreamsJava/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
Java/Scala Lab: Slava Schmidt - Introduction to Reactive Streams
 
Formal methods 5 - Pi calculus
Formal methods   5 - Pi calculusFormal methods   5 - Pi calculus
Formal methods 5 - Pi calculus
 

Más de Dr. C.V. Suresh Babu

Más de Dr. C.V. Suresh Babu (20)

Data analytics with R
Data analytics with RData analytics with R
Data analytics with R
 
Association rules
Association rulesAssociation rules
Association rules
 
Clustering
ClusteringClustering
Clustering
 
Classification
ClassificationClassification
Classification
 
Blue property assumptions.
Blue property assumptions.Blue property assumptions.
Blue property assumptions.
 
Introduction to regression
Introduction to regressionIntroduction to regression
Introduction to regression
 
DART
DARTDART
DART
 
Mycin
MycinMycin
Mycin
 
Expert systems
Expert systemsExpert systems
Expert systems
 
Dempster shafer theory
Dempster shafer theoryDempster shafer theory
Dempster shafer theory
 
Bayes network
Bayes networkBayes network
Bayes network
 
Bayes' theorem
Bayes' theoremBayes' theorem
Bayes' theorem
 
Knowledge based agents
Knowledge based agentsKnowledge based agents
Knowledge based agents
 
Rule based system
Rule based systemRule based system
Rule based system
 
Formal Logic in AI
Formal Logic in AIFormal Logic in AI
Formal Logic in AI
 
Production based system
Production based systemProduction based system
Production based system
 
Game playing in AI
Game playing in AIGame playing in AI
Game playing in AI
 
Diagnosis test of diabetics and hypertension by AI
Diagnosis test of diabetics and hypertension by AIDiagnosis test of diabetics and hypertension by AI
Diagnosis test of diabetics and hypertension by AI
 
A study on “impact of artificial intelligence in covid19 diagnosis”
A study on “impact of artificial intelligence in covid19 diagnosis”A study on “impact of artificial intelligence in covid19 diagnosis”
A study on “impact of artificial intelligence in covid19 diagnosis”
 
A study on “impact of artificial intelligence in covid19 diagnosis”
A study on “impact of artificial intelligence in covid19 diagnosis”A study on “impact of artificial intelligence in covid19 diagnosis”
A study on “impact of artificial intelligence in covid19 diagnosis”
 

Último

Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global Impact
PECB
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Krashi Coaching
 
1029 - Danh muc Sach Giao Khoa 10 . pdf
1029 -  Danh muc Sach Giao Khoa 10 . pdf1029 -  Danh muc Sach Giao Khoa 10 . pdf
1029 - Danh muc Sach Giao Khoa 10 . pdf
QucHHunhnh
 

Último (20)

Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"Mattingly "AI & Prompt Design: The Basics of Prompt Design"
Mattingly "AI & Prompt Design: The Basics of Prompt Design"
 
APM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across SectorsAPM Welcome, APM North West Network Conference, Synergies Across Sectors
APM Welcome, APM North West Network Conference, Synergies Across Sectors
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
 
Disha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdfDisha NEET Physics Guide for classes 11 and 12.pdf
Disha NEET Physics Guide for classes 11 and 12.pdf
 
microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introduction
 
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
Explore beautiful and ugly buildings. Mathematics helps us create beautiful d...
 
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
BAG TECHNIQUE Bag technique-a tool making use of public health bag through wh...
 
Sanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdfSanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdf
 
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
 
Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17
 
Measures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SDMeasures of Dispersion and Variability: Range, QD, AD and SD
Measures of Dispersion and Variability: Range, QD, AD and SD
 
Accessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impactAccessible design: Minimum effort, maximum impact
Accessible design: Minimum effort, maximum impact
 
fourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writingfourth grading exam for kindergarten in writing
fourth grading exam for kindergarten in writing
 
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
IGNOU MSCCFT and PGDCFT Exam Question Pattern: MCFT003 Counselling and Family...
 
Beyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global ImpactBeyond the EU: DORA and NIS 2 Directive's Global Impact
Beyond the EU: DORA and NIS 2 Directive's Global Impact
 
Paris 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activityParis 2024 Olympic Geographies - an activity
Paris 2024 Olympic Geographies - an activity
 
Student login on Anyboli platform.helpin
Student login on Anyboli platform.helpinStudent login on Anyboli platform.helpin
Student login on Anyboli platform.helpin
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
 
1029 - Danh muc Sach Giao Khoa 10 . pdf
1029 -  Danh muc Sach Giao Khoa 10 . pdf1029 -  Danh muc Sach Giao Khoa 10 . pdf
1029 - Danh muc Sach Giao Khoa 10 . pdf
 
Class 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdfClass 11th Physics NEET formula sheet pdf
Class 11th Physics NEET formula sheet pdf
 

ABA Problem

  • 1. ABA Problem Dr. C.V. Suresh Babu
  • 2. Introduction • Queues are everywhere in parallel applications and operating systems • Many researchers have proposed queues – – – – Hwang and Briggs Gottlieb Massalin Et al. etc… • Queue performance can be critical to operating system performance – Scheduling Queues – Free memory lists – Many other critical kernel operations
  • 3. Concurrent FIFO Queue algorithms • Blocking algorithms risk performance degradation – A process can be delayed or halted at inopportune moments • Scheduling preemption • Page faults • Cache misses – Slow processes can prevent faster ones from completing indefinitely • Non-Blocking algorithms must solve the ABA problem – During contention, some process will complete within a given number of operations
  • 4. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop value = SM newVal = value +1 Stack Data = d CAS(&SM, value, newVal) break Stack SM 5 … x time newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X
  • 5. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM newVal = value +1 Stack Data = d CAS(&SM, value, newVal) break Stack SM 4 … x time
  • 6. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d CAS(&SM, value, newVal) break Stack SM 4 … x time
  • 7. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Push(z) Stack Data = d CAS(&SM, value, newVal) break Stack SM 4 … x time
  • 8. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break Stack SM 4 … x time
  • 9. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break newVal=5 Stack SM 4 … x time
  • 10. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { loop newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break newVal=5 Stack CAS(&SM,value,newVal) SM 5 … z time
  • 11. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X loop CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break newVal=5 Stack CAS(&SM,value,newVal) CAS(&SM,value,newVal) SM 5 … z time
  • 12. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X loop CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break newVal=5 Stack CAS(&SM,value,newVal) CAS(&SM,value,newVal) v1=x SM 4 … z time
  • 13. ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data CAS(&SM, value, newVal) v1=Pop() value = 5 Push (d) { newVal = 4 data=X return data value = 5 newVal = 4 break v2=Pop() data=X loop CAS(&SM,value,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) CAS(&SM, value, newVal) value = 4 break newVal=5 Stack CAS(&SM,value,newVal) CAS(&SM,value,newVal) v1=x SM 4 … z CAS should fail but it succeeds time Thread1 has Thread2’s data
  • 14. Solutions for ABA problem Cache Kernel • Add version # to data structures • Increment # during every CAS instruction LL/SC • Fail if Cache Line has been written to
  • 15. Solution for ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data DCAS(&SM, value, v1=Pop() value = 5 return data Push (d) { newVal = 4 data=X break value = 5 newVal = 4 <ver++,newVal>) v2=Pop() data=X loop DCAS(&SM,value,ver,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) DCAS(&SM, value, value = 4 <ver++,newVal>) newVal=5 Stack break DCAS(&SM,value,ver,newVal) DCAS(&SM,value,ver,newVal) Will not incorrectly succeed SM 5 … z (ver != ver+2) time
  • 16. Solution for ABA problem Pop () { loop value = SM newVal = value -1 THREAD1 THREAD2 data = Stack Data DCAS(&SM, value, v1=Pop() value = 5 return data Push (d) { newVal = 4 data=Z break value = 5 newVal = 4 <ver++,newVal>) v2=Pop() data=X loop DCAS(&SM,value,ver,newVal) value = SM v2 = x newVal = value +1 Stack Data = d Push(z) DCAS(&SM, value, value = 4 <ver++,newVal>) newVal=5 Stack break DCAS(&SM,value,ver,newVal) DCAS(&SM,value,ver,newVal) Will not incorrectly succeed SM 4 (ver != ver+2) … time V1 = Z
  • 17. Correctness Properties 1. 2. 3. 4. 5. The linked list is always connected Nodes only inserted after the last node Nodes only deleted from beginning Head always points to the first node Tail always points to a node in the list
  • 18. Queue # 1 • Non-Blocking Concurrent Queue – enqueue()
  • 19. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value node–>next.ptr = NULL loop tail = Q–>Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node
  • 20. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node
  • 21. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node
  • 22. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node [NULL]
  • 23. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node [NULL]
  • 24. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node “enqueue(myQueue, D1)” enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) [NULL]
  • 25. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) [NULL]
  • 26. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL]
  • 27. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL] [NULL]
  • 28. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL] tail [NULL]
  • 29. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL] tail next [NULL]
  • 30. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL] tail next [NULL]
  • 31. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS( &tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 [NULL] tail next [NULL]
  • 32. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 +1 [NULL] tail next
  • 33. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 +1 [NULL] tail next
  • 34. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node enqueue(myQueue, D1) enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next +1 if tail == Q–>Tail if next.ptr == NULL if CAS(&tail.ptr–>next, next, <node, next.count+1>) myQueue break endif else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) endif endif endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) D1 +1 [NULL]
  • 35. Concurrent enqueues • Suppose two processes call enqueue() at the same time
  • 36. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS( &tail.ptr–>next, next, <node, next.count+1>) myQueue break Process 1 endif Enqueue(myQueue, ABC) else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) ABC endif endif [NULL] endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) tail next initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node D1 [NULL] Process 2 Enqueue(myQueue, XYZ) XYZ [NULL] tail next
  • 37. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS( &tail.ptr–>next, next, <node, next.count+1>) myQueue break Process 1 endif Enqueue(myQueue, ABC) else CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) ABC endif endif [NULL] endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) tail next initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node D1 +1 XYZ [NULL] Process 2 Enqueue(myQueue, XYZ) tail
  • 38. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } enqueue(Q: pointer to queue t, value: data type) node = new node() node–>value = value Head node–>next.ptr = NULL loop tail = Q–>Tail Tail next = tail.ptr–>next if tail == Q–>Tail if next.ptr == NULL if CAS( &tail.ptr–>next, next, <node, next.count+1>) myQueue break Process 1 endif Enqueue(myQueue, ABC) else CAS( &Q–>Tail, tail, <next.ptr, tail.count+1>) ABC endif endif [NULL] endloop CAS(&Q–>Tail, tail, <node, tail.count+1>) tail next initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node D1 +1 XYZ [NULL] Process 2 Enqueue(myQueue, XYZ) tail
  • 39. Queue #1 (cont.) • Non-Blocking Concurrent Queue – dequeue()
  • 40. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node “dequeue(myQueue, pvalue)” dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL]
  • 41. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 42. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 43. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 44. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 45. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head +1 tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 46. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head +1 tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 47. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head +1 tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL] head tail next
  • 48. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node dequeue(myQueue, pvalue) dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop Head head = Q–>Head +1 tail = Q–>Tail next = head–>next if head == Q–>Head Tail if head.ptr == tail.ptr if next.ptr == NULL return FALSE endif myQueue CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head, head, <next.ptr, head.count+1>) break endif endif endif endloop free(head.ptr) D1 [NULL]
  • 49. Concurrent dequeues • Suppose two processes call dequeue() at the same time
  • 50. struct pointer_t { node_t * ptr uint count } struct node_t { data_type value pointer_t next } struct queue_t { pointer_t Head pointer_t Tail } dequeue(Q: ptr to queue t, pvalue: ptr to data type):bool loop head = Q–>Head Head tail = Q–>Tail next = head–>next if head == Q–>Head if head.ptr == tail.ptr Tail if next.ptr == NULL return FALSE endif CAS(&Q–>Tail, tail, <next.ptr, tail.count+1>) else # Read value before CAS, otherwise another # dequeue might free the next node *pvalue = next.ptr–>value if CAS ( &Q–>Head,head, <next.ptr, head.count+1>) break endif “dequeue(myQueue, endif endif endloop free(head.ptr) return TRUE D1 [NULL] pvalue)”
  • 51. Queue #2 • Two-lock Concurrent Queue
  • 52. struct node_t { data_type value node_t * next } struct queue_t { pointer_t Head pointer_t Tail lock_type H_lock lock_type T_lock } initialize(Q: pointer to queue t) node = new node() node–>next.ptr = NULL Q–>Head = Q–>Tail = node Q–>H lock = Q–>T lock = FREE dequeue(Q: pointer to queue t, pvalue: pointer to data type): boolean lock(&Q–>H lock) node = Q–>Head new head = node–>next if new head == NULL enqueue(Q: pointer to queue t, value: data type) unlock(&Q–>H lock) node = new node() return FALSE node–>value = value endif node–>next.ptr = NULL *pvalue = new head–>value lock(&Q–>T lock) Q–>Head = new head Q–>Tail–>next = node unlock(&Q–>H lock) Q–>Tail = node free(node) unlock(&Q–>T lock) return TRUE • Algorithms have same general structure only different data types • No loops, ‘busy waiting’ instead • Only dequeues access Head Lock • Only enqueues access Tail Lock
  • 53. Performance Parameters • Net execution time for one million enqueue/dequeue pairs • 12-processor Silicon Graphics Challenge multiprocessor • Algorithms compiled with using highest optimization level • Including many hand optimizations
  • 54. Dedicated multiprocessor Multiprogrammed system with 3 processes per processor Multiprogrammed system with 2 processes per processor
  • 55. Conclusion • NBS clear winner for multiprocessor multiprogrammed systems • Above 5 processors, use the new nonblocking queue • If hardware only supports test-and-set use two lock queue • For two or less processors use a single lock algorithm for queues