Sign in to follow this  
69mij

Multithreading and c#

Recommended Posts

69mij    132
Greetings gamedevers!! I recently stumbled upon a problem and i'm hoping someone has the answer :) I have a small form in c# where upon clicking a button an image is drawn in a graphics object derived by the form itself pixel by pixel (the aim of that is to draw the mandelbrot fractal once complete). Now I wanted to have the pixel generation in a multithreaded environment so I divided the pixel space equally between the number of threads that exist. The problem is that since many threads try to draw something in the Graphics object derived by the form, then it crashes since apparently the draw functions cannot be executed in parallel. I tried to enclose the drawing process in between a mutex lock but it killed the benefits of multithreading. So what I ask is if it is possible to draw in a graphics object concurrently. I could write on an image and then show the image but i'd rather show the whole image as it is drawn rather than produce the output instantly after the end of the computation. Thanks in advance

Share this post


Link to post
Share on other sites
rip-off    10976
I'm not too familiar with C# so you'll have to adapt the terminology, but what you will want to do is create N distinct graphics objects, for each thread. Then, when all complete the resulting fragments are recombined by the main thread.

Share this post


Link to post
Share on other sites
69mij    132
Hmmm I didn't know if it is possible to create more than 1 graphics objects. I'll give it a shot and post the results.

Share this post


Link to post
Share on other sites
69mij    132
looks like i was able to create multiple graphics objects from one form and they accept multithreading draw commands but the overall execution time remains unchanged whether i have 1 thread or more which leads me to believe that the multiple graphics objects use some sort of critical section and hence serialize the whole process. Any ideas would be welcome again, thanks!

Share this post


Link to post
Share on other sites
Palidine    1315
Have all the calculations done in parallel and the rendering done in serial once the threads collapse.

each chunk calculates & stores the results
once a chunk is calculates it moves into the render thread and is rendered.

Basically separate queues for each thread, one of which is the rendering thread.

Remember you will gain no performance benefit if your threads are not on separate CPU cores. They should be scheduled automatically by the OS, I'm just saying this so you can double-check to make sure you haven't created more threads than you have physical cores.

-me

Share this post


Link to post
Share on other sites
69mij    132
Thanks for the reply firstly :)

Thing is that I have thought about it but i do want to show the image being generated as it is calculated rather than presenting an image at the end of the calculation :)

Also, I am aware that actual speedup will come only by the existence of multiple cores but since i have an i3 i hope i can see some speedup if i manage to get the parallelism right

Share this post


Link to post
Share on other sites
Palidine    1315
Quote:
Original post by 69mij
Thing is that I have thought about it but i do want to show the image being generated as it is calculated rather than presenting an image at the end of the calculation :)


Yeah you can do that as I presented it:

Take your calculation jobs split them into 2 threads (i3 has 2 cores). Each calculation job does the calculation and saves the results.

Once a calculation job it done, it gets put into the render thread's queue. The render thread is running in a loop that looks something like:

//assumes:
// (1) your queue is threadsafe
// (2) pop returns NULL if queue is empty
//potentially add another contidion here to make sure you don't spend
//too much time. so maybe: && timeElapsed < maxTimePerLoop
while ( (Job *j = popFromQueue()) != NULL )
{
j->render();
}
SwapBuffers();



Then you get:

1) parallel computation
2) serial rendering
3) display of computations as they happen

You'll have 2 threads running on one thread: likely render thread + a calculation thread. So it's possible that you may want some dynamic job load balancing between your calculate threads. But it'll probably just work fine without worrying about that to begin with.

-me

Share this post


Link to post
Share on other sites
MJP    19755
I'm not sure about how well GDI+ works with multiple threads, with regards to internal locks. Creating multiple Graphics objects from the same Image/Form sounds like a really bad idea, because ultimately those objects will have to serialize. You might be able to create several small Bitmaps, create a Graphics for each one, and then in each thread draw a portion of the final image to the small Bitmaps. Then in your main thread you could composite the smaller images onto the Form.

Share this post


Link to post
Share on other sites
djz    215
Quote:
Original post by MJP
I'm not sure about how well GDI+ works with multiple threads, with regards to internal locks. Creating multiple Graphics objects from the same Image/Form sounds like a really bad idea, because ultimately those objects will have to serialize. You might be able to create several small Bitmaps, create a Graphics for each one, and then in each thread draw a portion of the final image to the small Bitmaps. Then in your main thread you could composite the smaller images onto the Form.


MJP is correct that GDI+ is not threadsafe when used in this manner - it provides no functionality for synchronization. The solution outlined above will work to get around this.

What might work better is to create a master Bitmap as a buffer, lock the Bitmap and access the buffer directly across the threads, if all that's being done are set pixel operations.

As far as getting it to display in real-time as its drawn rather than back-buffering... I'd assume you would need direct access to the frame buffer to do this with pixel setting operations. You might want to look into SDL.Net.

edit: kudos to Palidine's elegant solution which I didn't read thoroughly before replying.

Share this post


Link to post
Share on other sites
Washu    7829
First off, don't use GDI+ for this. It should be noted that GDI is, in general, quite slow at drawing things, especially per pixel. Your best bet is to do bulk copies from non-GDI storage to GDI.

If you want to take your scene (say a texture) and divvy it up amongst your threads then assign each thread a work queue with a range determined by the host thread. Queue up all of the ranges, and let the ThreadPool class do the dispatching for you (QueueUserWorkItem).

Then, render to an array of Color's or whatever else you want to use. You can use the same array across all threads safely as long as their rendering regions do not overlap (that is: if thread1 does the range [0 -> 15] and thread2 does [16 - 31] then they can both safely access the same array without fear of writing over each other).

Then, once you've queued up all of your work items you have a couple of choices:
1. Have the main thread sit in a messaging wait state until the rendering completes, then once complete do a bulk copy from the backend array to the frontend bitmap, or
2. As each block completes have the main thread render that block to the appropriate part of the frontend bitmap.

Do not just block on the pool until all work items complete though (it'll make your application non-responsive during rendering...which is bad).

Share this post


Link to post
Share on other sites
69mij    132
The reason why i picked c# and opted for gdi was that i wanted to make a quick program fast and easily but apparently the infrastructure will not allow it easily. Anyways thanks all for your replies when i get around this problem again i will opt for directx :)

Share this post


Link to post
Share on other sites
mutex    1111
Quote:
Original post by Washu
First off, don't use GDI+ for this. It should be noted that GDI is, in general, quite slow at drawing things, especially per pixel. Your best bet is to do bulk copies from non-GDI storage to GDI.
GDI+ and GDI are mostly separate graphics APIs in implementation. Hardware acceleration of GDI was lost in Windows Vista but added again in Windows 7, and AFAIK most of GDI+ was never hardware accelerated.

Quote:
Original post by 69mij
The reason why i picked c# and opted for gdi was that i wanted to make a quick program fast and easily but apparently the infrastructure will not allow it easily. Anyways thanks all for your replies when i get around this problem again i will opt for directx :)
Another alternative is Direct2D, which is considerably easier to set up than Direct3D and provides more built-in 2D drawing operations.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this