Multithreading

Aug 9, 2009 at 10:31 AM

Hi,

I'm trying to use Multithreading. This seems to be easily done by returning UpdateFrequency.FullUpdate60hzAsync. After a few minor threading issues solved, I now run into something quite annoying. When the scene get's more complex and the drawing or updating cannot maintain a 60hz frequency it starts to get pulsing. (Draw .. .. Update .. Draw Update .. Update Draw). When two updates occur before a draw, the scene would seem to get a small speedboost for just a frame.

I've found a tutorial from Ziggyware that seems to benefit from multithreading, but will not suffer from this pulsing. This is because Update and Draw run on a separate thread, but will wait for each other each frame. I would like to try something simular in Xen. Let's say, create a couple of UpdateManagers on different threads, have them update themselves on that thread, and when each is done they synchronize to the draw thread.

Tutorial from ziggy: http://www.ziggyware.com/readarticle.php?article_id=221 

Is this possible to accomplish with the UpdateManager from Xen, or do I have to create my own UpdateManager for that?

Thanks!

Coordinator
Aug 10, 2009 at 8:34 AM
Edited Aug 11, 2009 at 5:46 AM

Multithreading in xen is designed to be handled through the ThreadPool (Xen.Threading.ThreadPool). The Application class has an instance of the ThreadPool already, and it's not recommended you create another. (So state.Application.ThreadPool).
This system has you perform your threading as actions / tasks.

When you use Async update frequencies, internally it just spawns a number of tasks that all update the group of objects with the same update frequency. There is overhead in doing this, and very simple update methods will actually end up slower with async, as the threads will all be battling for access to the list of objects needing update - stalling themselves and each other. So only do it if you have lots of objects with high workload (in which case the stalls won't happen - mostly removing the overhead). So very simple update methods will actually be very inefficient here. It's all part of why multithreading is a very very complex thing to do.
However, drawing and updating will never run at the same time. This is intended.

These tasks are in a few places internally. For example, animation calculation is spawned in a per-frame Update task, and then used in the following draw call.

So, if you wanted to do the threading pattern in that article, where you buffer data used during draw, the best option would be:

Break out your Update login into a separate method, implemented with the IAction interface (so PerformTask). Also store a WaitCallback, which is the structure used to see if a task is complete.

Then your (non asycn!) update method becomes:

//wait for the previous frame's task to complete
waitCallback.WaitForCompletion();

//buffer the data needed for Draw
BufferDrawData();

//spawn the new task
waitCallback = state.Application.ThreadPool.QueueTask(this,null);

return UpdateFrequency.FullUpdate60Hz;

Should be nice and simple. And then your update code runs in parallel with the rest of the application, using as many threads as available (just a frame behind).
You will avoid locks on data, and the thread pool uses few locks internally when processing. The waitcallback generally uses none unless the task hasn't completed yet.

Aug 10, 2009 at 9:29 PM

I think I've got the picture. Thank you for the detailed explaination!