0
\$\begingroup\$

I'm using XNA and all of my drawing is done in the main thread. I am CPU-bound and I thought I could gain performance by moving some non-update logic (like animation update) from the update loop into the draw loop and performing it in a parallel thread. This is the pseudocode:

Before:

void Update()
{
    foreach (var model in AllGameModels)
        model.UpdateAnimation();
}

After:

void UpdateAnimation()
{
    foreach (var model in AllGameModels)
        model.UpdateAnimation();
}
Thread UpdateAnimationThread;

void Draw()
{
    if (UpdateAnimationThread != null)
        UpdateAnimationThread.Join();
    UpdateAnimationThread = new Thread(UpdateAnimation);

    [main Draw code follows]
}

Unfortunately this always results in a significant DROP in performance. What can I be doing wrong? There is NO multithreading code in the Draw loop as it is simply impossible to do and I am not missing anything.

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Creating threads is expensive. If you’re going to perform animation processing each frame, it’s better to keep the thread around. Something like this:

void UpdateAnimationWorker()
{
    for (;;)
    {
        WaitForTrigger(); // waits for Draw() to signal us

        if (ShouldExit())
            break;

        foreach (var model in AllGameModels)
            model.UpdateAnimation();
    }
}

void Draw()
{
    AnimationTrigger(); // signal the animation thread

    [main Draw code follows]
}

There are lots of different ways to synchronise threads, and plenty of resources about threading in XNA. I suggest looking for “worker threads”. Also this MSDN thread seems to have good advice.

Also make sure that Draw() doesn’t rely on the results of UpdateAnimation(); in a typical game it does, and you don’t look like you have a mechanism to ensure that the results are ready before you draw them.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks, can I ask one more thing? Will it help to call Parallel.Foreach() inside this parallel thread? Or should I keep the code single-threaded there? \$\endgroup\$
    – cubrman
    Commented Apr 13, 2015 at 6:19
  • \$\begingroup\$ I have one more question: if this thread is always occupied, it will always impact things like Parallel.Foreach() called somewhere else in the code, right (that is they will run slower)? Even if this thread is in WaitForTrigger() state? Is there a way to minimize the thread's impact? Maybe Sleep() does that? \$\endgroup\$
    – cubrman
    Commented Apr 13, 2015 at 6:40
  • \$\begingroup\$ And one more thing :). How do you shut a thread down :)? And is there a way to ensure all the threads are closed when you exit the app in any way? \$\endgroup\$
    – cubrman
    Commented Apr 13, 2015 at 6:45
  • \$\begingroup\$ I've found a way to close the threads :). I can now see what was the main problem in our parallelization efforts - we were constantly creating threads, when we had to keep them active. Parallel.foreach has this issue too (i believe). That is a great discovery, thanks a lot! \$\endgroup\$
    – cubrman
    Commented Apr 13, 2015 at 7:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .