package org.openpixi.pixi.parallel.cellaccess; import org.openpixi.pixi.physics.grid.Grid; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; /** * Executes action upon cells in parallel using threads. * Can iterate also through extra cells based on the boolean parameter * includeExtraCells in constructor. */ public class ParallelCellIterator extends CellIterator { /* These are exposed here for inner classes since they can not be passed to them as method arguments. */ private Grid grid; private CellAction action; int numOfCells; private List<Callable<Object>> tasks = new ArrayList<Callable<Object>>(); private ExecutorService threadExecutor; public ParallelCellIterator(int numOfThreads, ExecutorService threadExecutor) { this.threadExecutor = threadExecutor; for (int i = 0; i < numOfThreads; ++i) { tasks.add(new Task(i, numOfThreads)); } } public void execute(Grid grid, CellAction action) { this.grid = grid; this.action = action; try { threadExecutor.invokeAll(tasks); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Override public void setNormalMode(int numCellsX, int numCellsY) { super.setNormalMode(numCellsX, numCellsY); numOfCells = dimensions.xsize() * dimensions.ysize(); } @Override public void setExtraCellsMode(int numCellsX, int numCellsY) { super.setExtraCellsMode(numCellsX, numCellsY); numOfCells = dimensions.xsize() * dimensions.ysize(); } private class Task implements Callable<Object> { private int threadIdx; private int numOfThreads; private Task(int threadIdx, int numOfThreads) { this.threadIdx = threadIdx; this.numOfThreads = numOfThreads; } public Object call() throws Exception { for (int cellIdx = threadIdx; cellIdx < numOfCells; cellIdx += numOfThreads) { int x = (cellIdx / dimensions.ysize()) + dimensions.xmin(); int y = (cellIdx % dimensions.ysize()) + dimensions.ymin(); action.execute(grid, x, y); } return null; } } }