Bpq,utq,ulfq (topic 9) Flashcards
what does bounded mean
fixed capacity
what does total mean?
a method is total if calls do not wait for conditions to become try
what does partial mean?
A method may wait for conditions to hold (suspending)
What does synchronous mean?
a method is synchronous if it waits for another method to overlap its call interval(A method call that adds an item to the pool is blocked until that item is removed by another method call)
Blocking vs Non-Blocking
Blocking: caller waits until state changes
Non-Blocking: Method throws exception
Does the enq and deq operate on the same sides of the queue?
no. so enq + deq should be able to proceed concurrently without interference. only concurrent calls will interfere
Properties of a queue(what is it and what does it consist of):
queue = linked list
queue has head and tail fields that refer to 1st and last nodes in list
queue contains a sentinel node (place-holder)
What are the 2 locks used(BQ)?
-deqlock (lock the front of the queue to ensure that there is not 1+ dequeuer at a time
-enqlock (lock end of queue to ensure that there is not more than one enqueuer at a time)
perks of 2 locks
enqueuers and dequeuers can operate independently
can enq calls continue while list is full and deq calls when list is empty?
No
What does the conditions do in the BPQ
notFullCondition = notify enqueuers when list is not full anymore
notEMptyCondition = notify dequeuers when list is not empty anymore
How do we keep track of the number of available slots in the BQ?
use a size field that is an AtomicInteger
code for the BoundedQueue class
public class BoundedQueue<T> {
ReentrantLock enqLock, deqLock;
Condition notEmptyCondition, notFullCondition;
AtomicInteger size;
Node head;
Node tail;
int capacity;
enqLock = new ReentrantLock();
notFullCondition = enqLock.newCondition();
deqLock = new ReentrantLock();
notEmptyCondition = deqLock.newCondition();
}</T>
enq code for bounded queue
public void enq(T x) {
boolean mustWakeDequeuers = false;
enqLock.lock();
try {
while (size.get() == capacity)
notFullCondition.await();
Node e = new Node(x);
tail.next = e;
tail = tail.next;
if (size.getAndIncrement() == 0)
mustWakeDequeuers = true;
} finally {
enqLock.unlock();
}
if (mustWakeDequeuers)
notEmptyCondition.signalAll();
}
}
}
deq code for bounded queue
public T deq() {
T result;
boolean mustWakeEnqueuers = false;
deqLock.lock();
try {
while (size.get() == 0)
notEmptyCondition.await();
result = head.next.value;
head = head.next;
if (size.getAndDecrement() == capacity)
mustWakeEnqueuers = true;
} finally {
deqLock.unlock();
}
if (mustWakeEnqueuers) {
notFullCondition.signalAll();
}
return result;
}}
Bad thing about deq + enq methods in BPQ
share atomic counter which is accessed on every method call
Solution with 2 counters in BPQ
enq: checks enqSideSize and proceeds as long as less than capacity
deq: checks deqSideSize and proceeds as long as greater than zero
UTQ enq:
public void enq(T x) {
enqLock.lock();
try {
Node e = new Node(x);
tail.next = e;
tail = tail.next;
} finally {
enqLock.unlock();
}
}
UTQ deq
public T deq() throws EmptyException {
T result;
deqLock.lock();
try {
if (head.next == null)
throw new EmptyException();
result = head.next.value;
head = head.next;
} finally {
deqLock.unlock();
}
return result;
}
ULFQ idea:
extension of unbounded queue.
prevents method calls from starving by having quicker threads help slower threads
ULFQ structure:
linked list. each nodes next = atomicReference (for lockfree operations)
LFQ node class
public class Node {
public T value;
public AtomicReference<Node> next;</Node>
public Node(T value) {
value = value;
next = new AtomicReference<Node>(null);
}
}</Node>
What are the 2 enqueue steps of the LFQ?
Logical enqueue - appends node to linked list
Physical enqueue - tail field to point to new node
are there 2 enqueue steps of the LFQ atomic?
no
What should you do if you find tail pointing to the wrong value in LFQ?
If tail node has non-null next field CAS the queues tail field to tail.next
ULFQ enq:
public void enq(T value) {
Node node = new Node(value);
while (true) {
Node last = tail.get();
Node next = tail.next.get();
if (last == tail.get()) {
if (next == null) {
if (last.next.compareAndSet(next, node)) {
tail.compareAndSet(last, node);
return;
} else
tail.compareAndSet(last, last.next);
}
}
}
}
ULFQ deq:
public T deq() throws EmptyException {
while (true) {
Node first = head.get();
Node last = tail.get();
Node next = first.next.get();
if (first == head.get()) {
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;
}
}}}