1

I'm new to multi-threading so all the other issues aside for a moment. I'm having trouble working out how to resolve my sprite batch being ended by the faster thread and the next thread causing "Object reference not set to an instance of an object".

Oh and if you can see anything else wrong with my code feel free to make me feel like an idiot ^^

spriteBatch.Begin();

// Draw Particles
List<Thread> threads = new List<Thread>();
for (int i = 0; i < CPUCores; i++)
{
    int tempi = i; // This fixes the issue with i being shared
    Thread thread = new Thread(() => DrawParticles(tempi + 1, CPUCores));
    threads.Add(thread);
    thread.Start();
}
foreach (var thread in threads)
{
    thread.Join();
}

// ..More Drawing Code..

spriteBatch.End(); // <-- This is where the program crashes

PS Who decided it was a good idea to use 4 spaces to signify code instead of [code] [/code]? ¬_¬

Shaun
  • 11
  • 2
  • 1
    Welcome to StackOverflow :-) the formatting of posts uses Markdown (which I find quite nice) and so that's where the 4 space formatting comes from. See http://stackoverflow.com/editing-help for more details. – Tomas Petricek Oct 01 '12 at 01:00

2 Answers2

3

Your problem comes from the fact that SpriteBatch is not thread-safe. By writing into the one sprite-batch from multiple threads, you're corrupting it.

SpriteBatch (except in Immediate mode) works kind of like a List of sprites (you wouldn't access one of those from multiple threads, would you?) or a buffer of sprites. So a possible solution to this is to have one SpriteBatch for each thread. Fill each sprite batch "buffer" by calling Draw inside that the thread.

Then, because you can only draw things on the main thread (ie: you can only call GraphicsDevice.Draw* on the main thread, which is what SpriteBatch.End calls internally), wait for your worker threads to finish filling each batch, and then call End on each of them from the main thread. This will draw the sprites to the screen.

Of course, a better technique, if you want to draw a huge number of particles, might be to offload everything to the GPU. Here is an answer that gives you a rough guide as to how you might do that.

Community
  • 1
  • 1
Andrew Russell
  • 26,924
  • 7
  • 58
  • 104
0

Graphics Device can only be accessed by one thread at a time, and SpriteBatch is not thread safe, so your draw calls should be sent from the main thread.

If you want to optimize your code for drawing more objects, DrawInstancedPrimitives will be much cleaner

http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drawinstancedprimitives-in-xna-game-studio-4-0.aspx

http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.graphicsdevice.drawinstancedprimitives.aspx

mrvux
  • 8,523
  • 1
  • 27
  • 61
  • Does anyone know why I'm getting more stuttering and generally lower fps using multithreading? Using 1 thread the program chokes around 280k particles, 2 threads 210k, 3 threads 180k. Also the drawing code is the bottleneck at the moment using just 1 core so I still don't understand the multithreading frame drops and stuttering. I have a i5-2500k @ 4.0GHz, 4x4GB 1600MHz RAM, HD 6870 1GB, 256GB C4 SSD. – Shaun Sep 29 '12 at 23:49
  • @catflier Instancing is a really *bad* choice for sprites. If it was a good choice, `SpriteBatch` would already be using the technique internally. Instancing is better when you have actual models. But you're certainly correct in saying that you can only draw from the main thread. – Andrew Russell Sep 30 '12 at 11:38