Concurrency with ”Double Thread”

Hello,

I have got a question regarding a concurrency issue.

I always use the enqueue method of the Application object when I call JME3 code from my Swing EventQueue. So far so good. If the code put to the Callable takes very long to execute it would be possible to wait for it within the Swing EventQueue to finish, what would be stupid due to the fact that you use Threads to perform tasks in parallel. However, it would look like this…

[java]



//Come from Swing EventQueue

Future<Mesh> meshFuture=application.enqueue(new Callable<Mesh>(){

public Mesh call() throws Exception{

Mesh mesh=calculateLargeMesh();

return mesh;

}

});

//Wait in Swing EventQueue until mesh has been calculated…

while(!meshFuture.isDone() && !meshFuture.isChancelled()){

//Give other threads possibility to go on.

Thread.yield();

}

//Go On in Swing EventQueue



[/java]

This would of course, be nonsense. So, I have created an Object

[java]

public abstract class SpecialThread<T> extends Thread {

public SpecialThread() {

}

@Override

public void run() {

//Call the JME EventQueue

Future<T> myTask = PraxitelesApplication.findInstance().getApplication().enqueue(new Callable<T>() {

@Override

public T call() throws Exception {

return processIt();

}

});

while (!myTask.isDone() && !myTask.isCancelled()) {

Thread.yield();

}

try {

finishIt(myTask.get());

} catch (InterruptedException ex) {

Exceptions.printStackTrace(ex);

} catch (ExecutionException ex) {

Exceptions.printStackTrace(ex);

}

}

public abstract T processIt();

public abstract void finishIt(T t);

}

[/java]

As you can see, I wrap the call to the JME3 Future in my own Thread. Now I can use such a construction…

[java]

new SpecialThread<Mesh>() {

@Override

public Mesh processIt() {

Mesh mesh=calculateLargeMesh();

return mesh;

}

@Override

public void finishIt(Mesh mesh) {

//Mesh is now definitely ready. Do what ever you want…

}

}.start();

[/java]

My questions are, if this is OK in this way, if you would propose using Executers instead, why would you propose using Executers.

Hope the problem is clear.

Thanks a lot.

Regards,

Equi

Generally you should decide which you consider your “main” thread and then only block that thread to any other thread that might be running. The problem with “independent” threads is that its easy to create a deadlock situation where each thread expects the other to run and deliver data at the same time. So in the cause of jMP the logic really happens on the AWT event dispatch thread and it reads and writes data to the OpenGL thread in a way similar to your first example if necessary. Normally is better not to block the main thread but simply chain the execution of the tasks. E.g. the AWT thread sends a callable to the OpenGL thread which in turn sends a call to the EDT using the AWT EventQueue when its finished with the operation.



Seeing all your endeavors I never really understood why you didn’t participate in development or at least use the jMP modules for your application since they implement all this already and provide ways to add your own extensions to all that. I guess you have already, but being this far now you might want to have a look at the development documentation of jMP a bit and then look at the jMP classes and how they implement this stuff.

Hi,



Thanks for help.

Yes, you are rigth. The development status of my scientific platform is far beyond using JME platform build ups or classes. The problem is that I have created a node - object structure that is so easy to use and extend that I don’t want to change it anymore. However, I’ll have a look at the platform source code and check how you did it there.

If I understood you correctly, you would propose to consider the EDT to be the main thread and if heavy calculation is performed, sending a Callable to the JME EventQueue and block in the EDT as long as the JME EventQueue thread has finished? I’ll go in this direction.



Thanks a lot.



Regards,

Equi

No I suggest not blocking the EDT but invoking it using a Callable at the end of the task being run on the OpenGL thread. This involves separating the code logic for this of course. If you must, yeah only block EDT against OpenGL, not vice versa (don’t use invokeAndWait() from OpenGL)

Hi,



So, you use LwjglAbstractDisplay, LwjglOffscreenBuffer etc. as your Runnable. These are the parallel Threads running next to my EDT. Within one of the Threads, you continuously call update method of Application, which polls the AppTasks and executes the Callables using call method. This means, if a heavy calculation in the call method of a Callable is performed, the blocking is performed in the JME Thread and my GUI continues running. If I understand it correctly your Application class is a kind of “Executor” like the Executers in Java concurrency package. Unfortunately, I don’t see how this solves my problem. It is true that I can create a Callable executing a heavy calculation code. This code is indeed processed on the parallel JME thread. However, I can only hold my EDT to wait for the result or perform my solution I have written at the very beginning of this topic. I would be interrested which solution you would propose for perfoming a parallel waiting, not holding the EDT.

Thanks a lot again.



Regards,

Equi

As said in every post since the beginning, invoke a callable back to the EDT!

[java]

Application.enqueue(new Callable() {

public Object call() throws Exception {

//do stuff on OGL thread HERE

java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {

//do stuff on EDT HERE

}

});

return null;

}

});

[/java]

You don’t need to do any calculation on the render thread. You only do things related to rendering on the render thread.



Calculating is not rendering.



You can use calculateLargeMesh() in the EDT or in your own thread, and when you need jME3 to render it you just attach it to the root node in the rendering thread by using callable. If you need to manipulate a live scene graph you can create a clone of your root node by using clone() or deepClone(), then detach the old one and attach the new one when the processing is done

It makes sense using the OpenGL thread as worker thread in this case as without a loaded model theres no reason to render stuff and the rest of the app goes on.