Threading and StandardGame

OK, I'm new to game design and have never touched threads, so this will probably be an incredibly naive set of questions, but I'll never have the answer if I don't ask. :slight_smile:



Until recently, I thought my audio subsystem was well-designed. I've since learned that this isn't the case, so I've had to switch to a heavier design. The result is that audio processing is a bit slower.



I'm using my own subclass of StandardGame in which I call my custom SoundSystem's update method. From a thread newbie's perspective, I guess this means I'm running my audio update code from within the OpenGL thread. With the new, more accurate audio system, I've noticed a marked drop in performance–from a minimum FPS value of 50-60 to in the 30s at times, particularly after a new sound is added or deleted, which requires creating a new source and buffering the audio.



Here's where my neivety shows. :slight_smile: I've optimized this about as well as I can. The SoundSystem merely adds/removes sounds from the list of those playing, while their positions and orientations are in custom nodes' updateGeometricState() methods which, presumably, are being updated by the GL thread. Should I really be running these subsystems in their own threads? Guessing this would prevent adding/removing of sounds from nearly halving my framerate, but on which level should I do this? Should I spawn a new thread when a new sound is added/removed (the CPU-intensive operations) or just call SoundSystem.update() again and again in its own separate thread?



I know there are various task managers, queues and such provided with JME. Would those help at all with this, or should I just suck it up and learn about threads? If the latter, can anyone recommend a good tutorial for someone with a clue but without prior experience with threads, other than of simply hearing how scary and error-prone they can be? :slight_smile: My use/experience with them thus far has been creating anonymous Runnable Thread instances when, say, I need to connect to my licensing/scoreboard server but don't want the music to stop or the game to block while the connection is pending.



And, from the perspective of StandardGame, where would be the best place to start a few threads that I'd like running throughout the lifetime of the application? I'm currently calling their update() methods in StandardGame's update(), but would run() be better?

First of all, I would suggest NEVER sublcassing StandardGame as it goes against the purpose of my writing it.  Anything you need to do should be able to be done without sub-classing, or you’re likely doing something wrong. :wink:



I would highly recommend learning about threading as it will be a huge help to you as a developer in many ways so you might as well get it over with.  The best tutorial I’ve found has been directly from Sun’s tutorials:

http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html



After you’ve gone through that you might have a better basis to make decisions, but I will say that you should be sparing in creating new threads.  You should always have a good reason for every thread you create.

darkfrog said:

First of all, I would suggest NEVER sublcassing StandardGame as it goes against the purpose of my writing it.
thewordnerd said:

In general I'd agree with this, as you've covered everything the, well, standard game would need in StandardGame. :) I'm writing an engine layer atop JME, overriding its audio system with my own and adding another subsystem for text-to-speech, and would ideally like to have my own StandardGame implementation that initializes both JME and my own subsystems such that any of my games can use it. The applications themselves won't subclass it--they'll use my custom subclass as normal.

As its creator, does this sound like a good reason for a subclass? If so, where would be the best place to launch my audio thread should I decide to go that route? Should I override run()?


No, I would suggest either creating a Controller and adding it to the scene of one your GameStates or creating an "AudioGameState" that would manage that, then simply turn off sound support inside StandardGame.

thewordnerd said:

Ah, OK, I tend to shy away from Sun tutorials as I've found them rather low-level and of the "throw a book at you all at once" variety (as opposed to the "start simple with practical examples" approach. :) I'll give it a read.


In some cases I would agree, but I think this is a very good read and important for any professional developer.

thewordnerd said:

OK, good piece of advice. So if I take this route then I should probably opt for the "single thread managing audio" approach, instead of the "spawn a new thread to handle every new/destroyed sound" route? Good to know, wasn't sure on which level I should be using threads, if at all.


Threading can often be a good way to reduce the level of complication in your application or resolve issues with aspects of your code that cause blocking.  Remember though, threads aren't magical (unless you have a multi-core machine in which case they are), they don't give you extra processors, they just abstract away the sharing of tasks, things can only happen one at a time.  Apart from multi-core machines if blocking did not exist there would be no need for threads.

Speaking of Threading…



Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?



Calling System.exit() from a non-deamon thread that's just hanging around doesn't seem correct to me. Maybe I'm just a stoggy ol' bastard.



My suggestion would be to have a waitForJoin() in the StandardGame implementation that does a gameThread.join(). Then instead of System.exit(), call into GameStateManager, allow it to loop through all the GameStates and allow them to clean up nicely before exiting the thread. (Maybe having the StandardGame use a finished flag on the GameStateManager instead of within itself.)



As it currently is the cleanup() and quit() methods of StandardGame don't usually get called.



Oddly, because you suggest not allowing the StandardGame to be extended the 'finished' member of StandardGame that would allow for cleaner shutdown is not accessible from any of the GameState extensions (see DebugGameState that catches the ESC for most Test examples).



— This is all not to say that I don't like the work. I do, very much so. I'm using myself, as is.

guurk said:

Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?


I would disagree there.  Since the thread started for StandardGame is not a daemon thread it will hang on until it is completed.  This allows you to start up anything that needs to be started in the main method and think of it more as an initialization block than the main loop of your application.  I don't see any reason why the main method completing causes any problems....can you give me an example of something?

guurk said:

Calling System.exit() from a non-deamon thread that's just hanging around doesn't seem correct to me. Maybe I'm just a stoggy ol' bastard.

As it currently is the cleanup() and quit() methods of StandardGame don't usually get called.

Oddly, because you suggest not allowing the StandardGame to be extended the 'finished' member of StandardGame that would allow for cleaner shutdown is not accessible from any of the GameState extensions (see DebugGameState that catches the ESC for most Test examples).


I agree there should be a better way to shut down the application but since there is a distinct abstraction between GameStates and the game they are connected to it makes that rather difficult.  I think this should be revised though eventually.

guurk said:

My suggestion would be to have a waitForJoin() in the StandardGame implementation that does a gameThread.join().


I don't really see a valid reason for this...perhaps you can clarify further?

guurk said:

Then instead of System.exit(), call into GameStateManager, allow it to loop through all the GameStates and allow them to clean up nicely before exiting the thread. (Maybe having the StandardGame use a finished flag on the GameStateManager instead of within itself.)


I agree there needs to be a way for GameStates to be able to shutdown the Game, and what you suggest might be a good way to be able to shutdown the GameStates, but still doesn't provide a clean way to call to the Game to tell it to stop.
darkfrog said:

guurk said:

Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?


I would disagree there.
guurk said:

darkfrog said:

guurk said:

Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?


I would disagree there.  Since the thread started for StandardGame is not a daemon thread it will hang on until it is completed.  This allows you to start up anything that needs to be started in the main method and think of it more as an initialization block than the main loop of your application.  I don't see any reason why the main method completing causes any problems....can you give me an example of something?


It doesn't cause any real problems... it's really just a coding convention thing. If there's plenty of documentation and a note that the main method shouldn't be ended with System.exit() I don't see anything wrong. It's just that neophytes my accidently kill their JVM and not know why nothing works when they assume too much.


Actually, staying in the launch thread would be a break in convention.

The common Java convention is you do what you need to setup in main and return.  AWT is much like JME in this regard, its spawns its own threads that continue to run.

@guurk, I'm not sure exactly what you're saying about not using System.exit() as in any case that will forcibly shut down the application.  The way StandardGame manages game threads shouldn't change anything in regards to System.exit() working…granted in ANY application (in my opinion) you shouldn't use System.exit() under normal conditions as the application should be able to gracefully shutdown without it simply by allowing all threads to gracefully shutdown.  Therein lies the problem though.  We need to come up with a better structure in order to allow some level of communication from the GameState to the Game.


jeffpk said:

Actually, staying in the launch thread would be a break in convention.

The common Java convention is you do what you need to setup in main and return.  AWT is much like JME in this regard, its spawns its own threads that continue to run.


Well, only StandardGame actually follows this principle as all other game implementations in jME have a start() method that is executed from main and executes everything in that main thread.  This is actually one of the reasons I wrote StandardGame is to be able to initialize everything from the main method without seeing blocking methods.
jeffpk said:

guurk said:

darkfrog said:

guurk said:

Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?


I would disagree there.  Since the thread started for StandardGame is not a daemon thread it will hang on until it is completed.  This allows you to start up anything that needs to be started in the main method and think of it more as an initialization block than the main loop of your application.  I don't see any reason why the main method completing causes any problems....can you give me an example of something?


It doesn't cause any real problems... it's really just a coding convention thing. If there's plenty of documentation and a note that the main method shouldn't be ended with System.exit() I don't see anything wrong. It's just that neophytes my accidentally kill their JVM and not know why nothing works when they assume too much.


Actually, staying in the launch thread would be a break in convention.

The common Java convention is you do what you need to setup in main and return.  AWT is much like JME in this regard, its spawns its own threads that continue to run.



The convention of having the main thread (or call) wait on the rest of the threads to finish comes from programming in C, in which the default handler when returning from main is to destroy all (non daemon) threads and exit.

It makes sense for Java not to follow this standard since its whole paradigm is different. In Java, threads are more tasks than only subdivision of computation.

PS. The quote was just to see how it looks to have 4 levels.  ;)  :D
duenez said:

jeffpk said:

guurk said:

darkfrog said:

guurk said:

Isn't it kind of bad form to allow the main() static method to exit without actually exiting the application?


I would disagree there.
darkfrog said:

I agree there needs to be a way for GameStates to be able to shutdown the Game, and what you suggest might be a good way to be able to shutdown the GameStates, but still doesn't provide a clean way to call to the Game to tell it to stop.


I think I've hit on a nice way to shut things down. I just put the StandardGame instance as a staic of the main class and call finish() from anywhere.


public class MyGame {
   public static final StandardGame game = new StandardGame("MyGame");
}




public class SomeState extends GameState {
protected InputHandler input;
public SomeState () {
   input = new InputHandler();
   input.addAction( new InputAction() {
      public void performAction( InputActionEvent evt) {
         MyGame.game.finish();
      }
   }, "exitGame", KeyInput.KEY_ESCAPE, false );
}
public void update( float tpf) {
   input.update( tpf);
}
}



Thoughts?

If I understand correctly, you want to include a new method called finish() on StandardGame, right? because AFAIK, currently StandardGame does not have one.  :?



If that is the case, then I have two comments:



  • What happens with threads, (like the GL, or some user created too) on shutdown? Is finish somehow aware of them too?

  • If the above is a non-issue, why not let the user decide where to call it, and let them not have the game state nor static reference to the game?


duenez said:

If I understand correctly, you want to include a new method called finish() on StandardGame, right? because AFAIK, currently StandardGame does not have one.

Ok, Ok… my bad!  :oops:



However, there is still the issue of user threads, right? finish does not call System.exit() (which is what you wanted to avoid in the first place), so user threads will still be alive.



Is it the intention that user threads should check the state of the game to see if it is active or not and exit gracefully?

@guurk, that's fine if you want to do that in your own code, but I just say, "yuck!". ;)  I think this is something that should be handled on a game-to-game basis, but I think what we need to solve is adding a destroy() method to GameState that GameStateManager.shutdown() would iterate over.  We could simply provide an empty destroy() method in GameState so it wouldn't break any existing code, but anyone that wants to add such support could simply override it.


duenez said:

If I understand correctly, you want to include a new method called finish() on StandardGame, right? because AFAIK, currently StandardGame does not have one.  :?

If that is the case, then I have two comments:


  • What happens with threads, (like the GL, or some user created too) on shutdown? Is finish somehow aware of them too?

  • If the above is a non-issue, why not let the user decide where to call it, and let them not have the game state nor static reference to the game?




Actually, finish() already does exist, but what guurk is saying is that he doesn't necessary have access to the "game" from the GameState to be able to call finish.  Also, I think I made a shutdown() method that might do some extra stuff in addition to finish(), but I don't have code in front of me so I don't remember.
duenez said:

Ok, Ok... my bad!