Thread Safety

Hi all,

Just ran a few thread tests and I noticed that the physics system is actually thread safe. From the very few and rough tests that I did, jme can maintain its own FPS as if the physics didn't even exists while the physics is running at 800 times a second. This means:


  1. You wont have to call update(float) anymore as this will be done internally from another thread.


  2. Most inaccuracies wont be noticed anymore as next few updates they will probably be fixed by ODE and with such a high update call, your eye will definetly not notice it.


  3. When the new processors with dual-cores come out, we'll already be supporting them…



    So im thinking now of moving the whole system to another thread and creating a "pause" method so that you can stop the simulation at any time…



    What do you think?



    DP

Sounds cool, what are the cons ?

Did you take into acccount that the jME scenegraph is not thread-safe? Eg if I add something to a Node and you're reading from it, mysterious things might happen. As long as you do the initialising of physics objects (which I assume are based on jME objects) from the jME thread, and make sure this is synchronized with the physics thread that part would work.



However, then there's the interaction the other way around, the physics engine controlling the geometry in the scene. That might be a problem…

Sorry, i didn't make myself clear in the post. The only thing that will run in the other thread is the update call. So yes, all the initing, adding of objects…etc will have to be made in the jme thread.



llama, yes i did think about that. I particularly thought about location/rotation settings when rendering. However, because the controller that is responsible for setting the location/rotation of the spatial from the physics representation is in infact a spatial controller which is called from the jme thread. So in that case, there isn't a problem.



In the tests that ive played with, ive set the thread-priority to the minimum, this gave me about 800 - 1200 updates a second, so im also going to write a simple method that will automagically calculate the step size based on the update frequency so that even when fluctuations in the update rate do occur, it wont be noticable. Most people who are using this engine are not using it for very accurate simulations of a physically accurate universe, so overall accuracy is not going to be important. What I mean by that is because the step size is going to vary, if you run the simulation a number of times, the box might not land at the same position it did last time. Either that, or we can restrict the update call frequency to say 300 times a second… I dont object either way.



So, any other thoughts?

Hm… so the controller you've implemented is thread safe? Now that I think of it, you might not even need locking, just transient variables. Good thing I put a "might" in "might be a problem".



Overall I think it's a good idea. I'm a fan of the idea of using threads to do the animation (which in essence is what physics does), and you're right: it is the future!

it is indeed the future, and yes, the controller that was implemented eons ago turned out to be thread safe. I'l implement it tomorrow, see if any of the tests break down and find a fix, the usual. When thats done, i'l post back here.



Regards,

DP

What exactly do you both mean with 'threadsafe'? The meaning known to me includes e.g. avoidance of racing conditions:

Example for jmephysics: If you read the coordinates of some spatial that is controlled by physics you can always be sure to read a consistent coordinate set.

This would not be the case in jme/jmephysics: The set and get methods in Vector3f are not syncronized this means your application code could possibly read x and y before a physics update and z after a physics update which would lead to pretty strange behaviour (at least for fast objects). jmephysics is definately not threadsafe (jme is not threadsafe, too) - there are probably situations where this does not matter althgough threads are used.



Multithreading leads to errors that are very hard to predict and to debug. I would recommend to stick at the current one-thread update - at least as default. Making a library thread safe (which is possible to some extend) always brings performance drawbacks with it. I don't think we really need multithreading as we already have a concept quite independent from the framerate.

Well irrisor, as DP told it, it sounds like all the updates to coordinates take place in update part in the controllers. You really shouldn't be messing with your scenegraph in the first place while these updates are running. If you want to have some other thread than the jME thread updating coordinates you should follow the same approach as DP, read and write to all Vector3f from the jME thread itself.

To avoid those racing conditions that you stated irrisor, its a simple matter of adding a boolean value that is set to true when the system is updating. In the controller, make sure its false when updating the spatial…thats it.



Also, adding/removing objects will have to be cached because adding/removing object when the world is being updated causes errors, so cache them and deal with them from the jme-thread once update has finished.



That really is all that need to be considered and I do think the advantages from multi-threading does currently heavily outweigh the reasons not to.



DP

Whoops looks like I missed quite some part of the facts  :expressionless: I did not really get that the coordinate updates should be kept in the jME thread via a controller - sorry



So I only have one question left then: what about the collision results? In what thread will they be handled? Should be in the jME thread, shouldn't it?

Do you think of a queue or similar to hand them over from the physics/ode thread?

Basically, its up to us to make the library thread-safe. Its up to the user to create a new thread and call update from that new thread that they created. This is good for two reaons. First is that the engine can stay single-threaded if the user wants to. And two, they can obtain the collision results themselves in that new thread.



The code snippet is like:



Thread updateT = new Thread(new Runnable() {
         
         public void run() {
            while (true) {
               results = PhysicsWorld.getInstance().update(tpf);
               Thread.yield();
            }
         }
      });
      updateT.setPriority(Thread.MIN_PRIORITY);
      updateT.start();



Or whatever the user prefers...

Thats my take on it anyway, and thats how I prefer it to be. But if anyone has any other thoughts...please do chime in.

Regards,
DP

Could you not make add a method for this?

no, due to syncing problems, the update might be compiling the list of collisions and adding them into results while your getting them. Meaning you will only get a portion of the actual results…



DP

Hmm, to let the library-user call update in an own thread brings back my racing-condition-headaches again: He will most probably try to handle the results in there, too, which will cause problems with either his own entities (if used in the jmethread, too) or the spatials…

I must admit that it is probably desirable to run the ode-computation in a different thread. But I would not encourage the user to fork an own thread - this should only be done by users who really know what they are doing!

So what about the queue - in jmephysics do this (a bit pseudocode)

Thread updateT = new Thread(new Runnable() {
   public void run() {
      while (!isTerminated()) {
         results = PhysicsWorld.getInstance().update(tpf);
         getCollisionQueue().addAll( results );
         Thread.sleep(timeUntilNextUpdate);
      }
   } });
updateT.setPriority(Thread.MIN_PRIORITY);
updateT.start();



In the app (in jme thread) do somehting like that:

Queue collisions = PhysicsWord.getInstance().getCollisionQueue();
while ( collisions.peek() != null )
{
   handleCollisionResult( collisions.poll() );
}



Maybe we should add a timestamp to the CollisionResults in this case, and provide methods to clean old results (automatically?) or put them into the queue only if it is polled...