WorkerThread, how to pass an undefined method to be executed..?

Well, read my post?

I did, and I’m confused as to why there is an extra layer of indirection.
I’m also saying that the solution already exists in the stdlib.

For defining wrappers around tasks use FutureTask.
Program organization (BlockingQueue etc. at start of loop) is a separate issue.

Actually I was refering to the program organization when writing my post, since the problem with offloading arbitrary stuff to an external thread is that you have to manage what to do with the result, etc. somehow. This is difficult, if the isDone() polling and get()-result handling is in the gameloop, while the executor call is somewhere completely else. So having the callback, ensures that you don’t have to put your code all over the place.

But yes, I should not have divagated to Guava, so here is an implementation without it:


  // this rolls the callable and the callback in one interface
  public interface CallbackCallable<T> extends Callable<T>
  {
    // while the call() from callable should be called on the thread of the thread-pool
   
    // the following two should run on the gl thread
    void onSuccess(T result);
    void onFailure(Throwable thrown);
  }

  // ...

  // to get over the result from the future to the gl thread, a bridge is needed
  public class GLThreadBridge
  {
    // this connects the Future with the Callable that created it.
    private static class CallbackHolder<T>
    {
      Future<T> future;
      CallbackCallable<T> callback;

      public CallbackHolder(Future<T> future, CallbackCallable<T> callback)
      {
        this.future = future;
        this.callback = callback;
      }
    }

    // the pool
    private final ExecutorService pool = Executors.newFixedThreadPool(7);
    // and the callback queue
    private final ConcurrentLinkedQueue<CallbackHolder> holders = new ConcurrentLinkedQueue<CallbackHolder>();

    // to submit the tasks
    public <T> void submit(CallbackCallable<T> task)
    {
      holders.add(new CallbackHolder<T>(pool.submit(task), task));
    }

    // this handles the future polling and result callback calls
    public void handleFinished()
    {
      for (Iterator<CallbackHolder> iterator = holders.iterator(); iterator.hasNext(); )
      {
        CallbackHolder holder = iterator.next();
        try
        {
          if(holder.future.isCancelled())
            throw new InterruptedException("Task was cancelled");

          if(holder.future.isDone())
          {
            holder.callback.onSuccess(holder.future.get());
            iterator.remove();
          }
        }
        catch (Throwable t)
        {
          iterator.remove();
          holder.callback.onFailure(t);
        }
      }
    }
  }

Now you can use the bridge to submit callables with integrated callbacks:


  // put this somewhere, you can access it
  GLThreadBridge glThreadBridge=new GLThreadBridge();

  // ...

  // this is an example how to use the submit method...
  void offloadToPool()
  {
    glThreadBridge.submit(
      new CallbackCallable<Chunk>()
      {

        // will be called on external thread
        @Override
        public Chunk call() throws Exception {
          return loadChunk();
        }

        // will be called from gameloop
        @Override
        public void onSuccess(Chunk loaded) {
          // do something with loaded
        }

        // will be called from gameloop
        @Override
        public void onFailure(Throwable thrown) {
          // handle a failure somehow
        }
      }
    );
  }

To move execution of the onSuccess()/onFailure() methods to the gameloop/gl-thread, handleFinished() has to be called at the beginning of the loop:


  // and this shows how to integrate it in the gameloop...
  void gameLoop()
  {
    while(true)
    {
      glThreadBridge.handleFinished();
      //...
    }
  }

Disclaimer: I just wrote it down and didn’t try it, so it might need more work to actually… well… work :wink: