0

I have a program that uses state-space searching algorithms (A*, IDA*, etc.) to solve some problem. I would like to run ~30-50 test iterations to get some information (average runtime, expanded nodes, etc.), but my issue is, sometimes these algorithms can take a very long time to solve the problem. I'd like to have the option to set a timeout on the method calls to limit the execution time (so I can for example run the tests overnight and have them finish reliably).

Assume the Solvers (classes implementing the algorithms) are provided as-is and cannot be altered. They are utilised by calling their solve method, which returns a List<Integer>.

This is the relevant piece of the code I'm currently using, courtesy of a similar thread here on stackoverflow:

int nTests = 50;
long timeout = 120;
double[] expandedAvg = new double[solvers.size()];        // averages of expanded nodes for each solver
int[] fails = new int[solvers.size()];        // number of timeouts for each solver

for (int i = 1; i <= nTests; i++) {
    int[][] problem = createProblem();         // creates a random solvable problem
    int j = 0;
    for (Solver solver : solvers) {
        boolean success = true;
        List<Integer> solution = null;

        if (timeout > 0) {
            Callable<List<Integer>> task = new Callable<List<Integer>>() {
                @Override
                public List<Integer> call() {
                    return solver.solve(problem);
                }
            };
            Future<List<Integer>> future = Executors.newCachedThreadPool().submit(task);
            try {
                solution = future.get(timeout, TimeUnit.SECONDS);
            }
            catch (TimeoutException e) {
                success = false;
                System.out.println("FAIL");
            }
            catch (InterruptedException ignore) {}
            catch (ExecutionException e) {
                e.printStackTrace();
            }
            finally {
                future.cancel(true);
            }
        }
        else solution = solver.solve(problem);

        if (success) {
            // update the average
            expandedAvg[j] = expandedAvg[j] + (solver.expanded - expandedAvg[j]) / (i - fails[j]);
        }
        else fails[j]++;

        j++;
    }
}

What ends up happening, however, is that after the first failed solve attempt, all further attempts fail as well. The issue appears to be that future.cancel(true) does not actually stop the execution of the solver (I'm basing this guess on the fact that the entire application does not terminate after the end of the outer loop, which means something is still running in another thread), which then hogs all the resources, and the successive ones don't get any CPU time (and consequently fail). If it matters, I'm running this from Eclipse.

Is there a way to ensure the threads get stopped when timed out? Or is there maybe another way of implementing timeouts I should use?

Mate de Vita
  • 1,102
  • 12
  • 32
  • 1
    Your `Solver` needs actually some logic to handle a cancelation. Java does not cancel the taks for you if has already started execution. [This question](http://stackoverflow.com/questions/1418033/java-executors-how-can-i-stop-submitted-tasks) depicts one possible solution for your problem (although it will always involve modifying the `Solver`...) – Turing85 Jun 09 '16 at 21:07
  • 1
    I would consider running the solvers in sub-processes. – Solomon Slow Jun 09 '16 at 21:25
  • If all you need is just terminate an entire application due to whatever condition, then you can use `System.exit(0);` Otherwise there is no 100% thread-safe (or indeed data-safe) method to force-stop running thread. All those deprecated methods like `Thread.stop()` are not recommended for good reasons. – Andrey Lebedenko Jun 09 '16 at 21:50

0 Answers0