package edu.stanford.rsl.conrad.parallel;
import ij.IJ;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import edu.stanford.rsl.conrad.utils.CONRAD;
/**
* Class to execute multiple ParallelizeableRunnables in parallel. The Executor will dispatch
* as many ParallelizedRunnables as there are CPUs in the machine on which the code is executed in one batch.
* Then it will wait until all processes in the current batch are done. As soon as this is the case a new batch
* of processes is started. This is done until all ParallelizableRunnables are processed.
*
* @author Andreas Maier
*
*/
public class ParallelThreadExecutor {
private boolean showStatus;
ParallelizableRunnable [] runnables;
boolean debug = false;
private CountDownLatch latch;
public static boolean parallel = true;
public void setShowStatus(boolean showStatus) {
this.showStatus = showStatus;
}
public boolean isShowStatus() {
return showStatus;
}
/**
* In order to have the threads performed in parallel just an Array of ParallelizableRunnables is
* passed to the contructor of the ParallelThreadExecutor.
* @param runnables the processes to run.
*/
public ParallelThreadExecutor(ParallelizableRunnable [] runnables){
this.runnables = runnables;
}
public ParallelThreadExecutor(ParallelizableRunnable [] runnables, int latchSize){
this.runnables = runnables;
latch = new CountDownLatch(latchSize);
}
/**
* This method will start the processing.
* @throws InterruptedException may occur.
*/
public void execute() throws InterruptedException{
int numThreads = CONRAD.getNumberOfThreads();
if (showStatus) CONRAD.log("Number of used processors: " + numThreads);
if (numThreads > 7) if (showStatus) CONRAD.log("I like this machine ... ");
Future <?> [] futures = new Future<?>[runnables.length];
if (debug) System.out.println("Starting new batch ...");
ExecutorService e = Executors.newFixedThreadPool(numThreads);
// initialize the parallel processing.
long latchSize = 0;
if(latch == null) {
latch = new CountDownLatch(runnables.length);
latchSize = runnables.length;
} else {
latchSize = latch.getCount();
}
if (parallel) {
parallel = false;
// invoke the threads
for (int i = 0; i < runnables.length; i++){
runnables[i].setLatch(latch);
futures[i] = e.submit(runnables[i]);
}
// wait for all jobs to be done
while (latch.getCount() > 0){
if (showStatus){
int i = (int) (latchSize - latch.getCount());
if (i < runnables.length){
if (runnables[i] instanceof NamedParallelizableRunnable)IJ.showStatus("Running " + ((NamedParallelizableRunnable)runnables[i]).getProcessName());
}
IJ.showProgress((i + 0.0) / latchSize);
}
Thread.sleep(CONRAD.INVERSE_SPEEDUP);
}
e.awaitTermination(1000, TimeUnit.MILLISECONDS);//e.shutdownNow();
e = null;
if (showStatus) IJ.showProgress(1.0);
parallel = true;
} else {
//System.out.println("Debug mode. Invoking sequentially.");
for (int i = 0; i < runnables.length; i++){
runnables[i].setLatch(latch);
//System.out.println("Thread " + i);
runnables[i].run();
}
//System.out.println("All done.");
}
}
}
/*
* Copyright (C) 2010-2014 Andreas Maier
* CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
*/