//
// Copyright (C) 2011 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
/**
* concurrency example with deadlock
* adapted from "Concurrency: State Models & Java Programs", Jeff Magee & Jeff Kramer
*
* Note there need to be at least 2x buffer_size instances of either producers or
* consumers in order to produce the deadlock, which basically depends on
* a notification choice between a consumer and a producer in a context where
* only threads of the notifier type are still runnable
*
* This is a good benchmark for state management/matching in a small heap context.
* Higher numbers of buffer size and producers/consumers result in a nice
* state explosion
*/
public class BoundedBuffer {
static int BUFFER_SIZE = 1;
static int N_PRODUCERS = 4;
static int N_CONSUMERS = 4;
static Object DATA = "fortytwo";
//--- the bounded buffer implementation
protected Object[] buf;
protected int in = 0;
protected int out= 0;
protected int count= 0;
protected int size;
public BoundedBuffer(int size) {
this.size = size;
buf = new Object[size];
}
public synchronized void put(Object o) throws InterruptedException {
while (count == size) {
wait();
}
buf[in] = o;
//System.out.println("PUT from " + Thread.currentThread().getName());
++count;
in = (in + 1) % size;
notify(); // if this is not a notifyAll() we might notify the wrong waiter
}
public synchronized Object get() throws InterruptedException {
while (count == 0) {
wait();
}
Object o = buf[out];
buf[out] = null;
//System.out.println("GET from " + Thread.currentThread().getName());
--count;
out = (out + 1) % size;
notify(); // if this is not a notifyAll() we might notify the wrong waiter
return (o);
}
//--- the producer
static class Producer extends Thread {
static int nProducers = 1;
BoundedBuffer buf;
Producer(BoundedBuffer b) {
buf = b;
setName("P" + nProducers++);
}
public void run() {
try {
while(true) {
// to ease state matching, we don't put different objects in the buffer
buf.put(DATA);
}
} catch (InterruptedException e){}
}
}
//--- the consumer
static class Consumer extends Thread {
static int nConsumers = 1;
BoundedBuffer buf;
Consumer(BoundedBuffer b) {
buf = b;
setName( "C" + nConsumers++);
}
public void run() {
try {
while(true) {
buf.get();
// Object tmp = buf.get();
}
} catch(InterruptedException e ){}
}
}
//--- the test driver
public static void main(String [] args) {
readArguments( args);
//System.out.printf("running BoundedBuffer with buffer-size %d, %d producers and %d consumers\n", BUFFER_SIZE, N_PRODUCERS, N_CONSUMERS);
BoundedBuffer buf = new BoundedBuffer(BUFFER_SIZE);
for (int i=0; i<N_PRODUCERS; i++) {
new Producer(buf).start();
}
for (int i=0; i<N_CONSUMERS; i++) {
new Consumer(buf).start();
}
}
static void readArguments (String[] args){
if (args.length > 0){
BUFFER_SIZE = Integer.parseInt(args[0]);
}
if (args.length > 1){
N_PRODUCERS = Integer.parseInt(args[1]);
}
if (args.length > 2){
N_CONSUMERS = Integer.parseInt(args[2]);
}
}
}