I am reading The Art of Multiprocessor Programming, 2ed and I noticed the following pattern is used to read several Atomic*
fields:
while (true) {
var v1 = atomic1.get();
var v2 = atomic2.get();
...
var vN = atomicN.get();
if (v1 == atomic1.get()) {
// do work
}
}
What is the purpose of this construction?
The only explanation I found in the book is:
... checks that the values read are consistent ...
I don't understand this explanation.
Here is LockFreeQueue
, which uses this pattern, from the book:
public class LockFreeQueue<T> {
AtomicReference<Node> head, tail;
public LockFreeQueue() {
Node node = new Node(null);
head = new AtomicReference(node);
tail = new AtomicReference(node);
}
public void enq(T value) {
Node node = new Node(value);
while (true) {
Node last = tail.get();
Node next = last.next.get();
if (last == tail.get()) { // <=== WHY: reading tail.get() again
if (next == null) {
if (last.next.compareAndSet(next, node)) {
tail.compareAndSet(last, node);
return;
}
} else {
tail.compareAndSet(last, next);
}
}
}
}
public T deq() throws EmptyException {
while (true) {
Node first = head.get();
Node last = tail.get();
Node next = first.next.get();
if (first == head.get()) { // <=== WHY: reading head.get() again
if (first == last) {
if (next == null) {
throw new EmptyException();
}
tail.compareAndSet(last, next);
} else {
T value = next.value;
if (head.compareAndSet(first, next))
return value;
}
}
}
}
}
public class Node {
public T value;
public AtomicReference<Node> next;
public Node(T value) {
this.value = value;
next = new AtomicReference<Node>(null);
}
}
I saw another similar question on SO: Lock-free queue algorithm, repeated reads for consistency.
But:
- the accepted answer has negative score and states that all would work without repeated reads, but offers no proofs
- it discusses a different algorithm: that algorithm frees nodes explicitly, while the book is mostly about algorithms in java (where nodes are freed implicitly by the GC).
UPD: the book says that LockFreeQueue
is a slightly simplified version of a queue algorithm by Maged Michael and Michael Scott.
This is the same algorithm as the one discussed in the similar SO question mentioned above.