package org.multiverse.stms.gamma.integration.classic; import org.junit.Before; import org.multiverse.TestThread; import org.multiverse.api.Txn; import org.multiverse.api.TxnExecutor; import org.multiverse.api.callables.TxnCallable; import org.multiverse.api.callables.TxnVoidCallable; import org.multiverse.api.references.TxnInteger; import org.multiverse.stms.gamma.GammaStm; import static junit.framework.Assert.assertEquals; import static org.multiverse.TestUtils.*; import static org.multiverse.api.GlobalStmInstance.getGlobalStmInstance; import static org.multiverse.api.StmUtils.newTxnInteger; import static org.multiverse.api.StmUtils.retry; import static org.multiverse.api.TxnThreadLocal.clearThreadLocalTxn; /** * http://en.wikipedia.org/wiki/Producer-consumer_problem */ public abstract class ProducerConsumer_AbstractTest { private Buffer buffer; private volatile boolean stop; private static final int MAX_CAPACITY = 100; protected GammaStm stm; protected abstract TxnExecutor newPutBlock(); protected abstract TxnExecutor newTakeBlock(); @Before public void setUp() { clearThreadLocalTxn(); stm = (GammaStm) getGlobalStmInstance(); stop = false; } public void run() { buffer = new Buffer(); ProducerThread producerThread = new ProducerThread(); ConsumerThread consumerThread = new ConsumerThread(); startAll(producerThread, consumerThread); sleepMs(30 * 1000); stop = true; joinAll(producerThread, consumerThread); assertEquals(producerThread.produced, buffer.size.atomicGet() + consumerThread.consumed); } public class ProducerThread extends TestThread { private int produced; public ProducerThread() { super("ProducerThread"); } @Override public void doRun() { produced = 0; while (!stop) { buffer.put(produced); produced++; if (produced % 1000000 == 0) { System.out.printf("%s is at %d\n", getName(), produced); } } buffer.put(-1); produced++; } } public class ConsumerThread extends TestThread { public int consumed; public ConsumerThread() { super("ConsumerThread"); } @Override public void doRun() { int item; do { item = buffer.take(); consumed++; if (consumed % 1000000 == 0) { System.out.printf("%s is at %d\n", getName(), consumed); } } while (item != -1); } } class Buffer { private final TxnInteger size = newTxnInteger(); private final TxnInteger[] items; private final TxnExecutor takeBlock = newTakeBlock(); private final TxnExecutor putBlock = newPutBlock(); Buffer() { this.items = new TxnInteger[MAX_CAPACITY]; for (int k = 0; k < items.length; k++) { items[k] = newTxnInteger(); } } int take() { return takeBlock.execute(new TxnCallable<Integer>() { @Override public Integer call(Txn tx) throws Exception { if (size.get() == 0) { retry(); } size.decrement(); return items[size.get()].get(); } }); } void put(final int item) { putBlock.execute(new TxnVoidCallable() { @Override public void call(Txn tx) throws Exception { if (size.get() >= MAX_CAPACITY) { retry(); } items[size.get()].set(item); size.increment(); } }); } } }