package si.pele.concurrent.leftright; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; /** * Implementation of the basic "Left Right" algorithm described in paper: * * Left-Right: * A Concurrency Control Technique with Wait-Free Population Oblivious Reads * * by Pedro Ramalhete and Andreia Correia * */ public class LeftRight { private volatile T leftState; private volatile EnterExitWait leftReaders; private T rightState; private EnterExitWait rightReaders; private final Object lock = new Object(); public LeftRight(T leftState, T rightState) { this(leftState, new LongAdderEEW(), rightState, new LongAdderEEW()); } public LeftRight(T leftState, EnterExitWait leftReaders, T rightState, EnterExitWait rightReaders) { this.leftState = leftState; this.leftReaders = leftReaders; this.rightState = rightState; this.rightReaders = rightReaders; } public R read(Function readFunction) { return read(readFunction, Function::apply); } public void modify(Consumer modifyConsumer) { modify(modifyConsumer, Consumer::accept); } public R read(P param, BiFunction readFunction) { // read leftReaders 1st EnterExitWait lr = leftReaders; lr.enter(); try { // read leftState 2nd return readFunction.apply(param, leftState); } finally { lr.exit(); } } public

void modify(P param, BiConsumer modifyConsumer) { synchronized (lock) { // modify rightState T rs = rightState; modifyConsumer.accept(param, rs); // swap left<->right state 1st T ls = leftState; rightState = ls; leftState = rs; // wait for rightReaders to complete EnterExitWait rr = rightReaders; rr.waitEmpty(); // swap left<->right readers 2nd EnterExitWait lr = leftReaders; rightReaders = lr; leftReaders = rr; // wait for ex-leftReaders (now-rightReaders) to complete lr.waitEmpty(); // modify ex-leftState (now-rightState) modifyConsumer.accept(param, ls); } } }