views:

87

answers:

2

(Edit: to clarify, my main goal is concurrency, but not necessarily for multi-core machines)

I'm fairly new to all concepts on concurrency, but I figured out I needed to have parallel drawing routines, for a number of reasons:

  • I wanted to draw different portions of a graphic separatedly (background refreshed less often than foreground, kept on a buffer).
  • I wanted control about priority (More priority to UI responsiveness than drawing a complex graph).
  • I wanted to have per-frame drawing calculations multithreaded.
  • I wanted to offer cancelling for complex on-buffer drawing routines.

However, being such a beginner, my code soon looked like a mess and refactoring or bug-fixing became so awkward that I decided I need to play more with it before doing anything serious.

So, I'd like to know how to make clean, easy to mantain .NET multithreaded code that makes sense when I look at it after waking up the next day. The bigest issue I had was structuring the application so all parts talk to each other in a smart (as opposed to awkward and hacky) way.

Any suggestion is welcome, but I have a preference for sources that I can digest in my free time (e.g., not a 500+ pages treatise on concurrency) and for C#/VB.NET, up to the latest version (since I see there have been advances). Basically I want something straight to the point so I can get started by playing with the concepts on my toy projects.

+2  A: 

The Task Parallel Library is definitely the place to look for simplifying your code. I've personally written a (semi-long) introduction to Parallelism with .NET 4 that covers quite a few concepts that would be useful.

Be aware, however, that you probably will want to consider leaving your drawing single threaded. You should try to keep the computation multithreaded, and the actual drawing operations done on the GUI thread.

Most drawing APIs require all actual drawing calls to happen on the same synchronization context.

That being said, using the new collection classes like ConcurrentQueue simplify this type of code. Try to think in terms of lots of threads (producers) adding "drawing operations" to a shared, concurrent queue - and one thread (the consumer) grabbing the operations and performing them.

This gives you a reasonably scalable, but fairly simple design on which you can build.

Reed Copsey
Hehe I have one of your introduction's articles already open in another tab and I must say it's awesome (and the best source I've found so far), I'm quickly taking insight from it. Regarding drawing code, as I've said the "background" is slightly more complex (and it could be drawn in a buffer while lightweight elements are overlaid on the previous background buffer), but the main problem I face is sharing such buffers in an elegant fashion across threads (and calling the rendering functions on the right time as opposed to placing them on the paint event).
Camilo Martin
I'll keep reading your articles and fiddling with code, maybe that is worth more than a big book on the subject (for my humble coder needs). For now, +1 and unlimited kudos to you! :)
Camilo Martin
@Camilo: FYI - Best book I've seen on this so far is the P) ). It'll be released next month, but you can read the preview at: http://parallelpatterns.codeplex.com/
Reed Copsey
Seems really good, surely a nice read to dig deeper into the topic, too bad for them because your articles leave little room for further introduction :)
Camilo Martin
I'll accept your answer because your articles helped me so much.
Camilo Martin
+1  A: 

but I figured out I needed to have parallel drawing routines

Three words: NOT UNDER WINDOWS.

Simple like that. Standard windows drawing is single threaded per definition, for compatibility reasons. Any UI control (let's stick to the .NET world) shall ONLY be manipulated from it's creational thread (so in reality it is more brutal than single threaded - it is ONE SPECIFIC THREAD ONLY).

You can do the precalculation separately, but the real drawing has t obe done from that one thread.

UNLESS you allocate a bitmap, have your own drawing there, and then turn that over to the UI thread for painting onto the window.

This has nothing to do with the whole Task Parallel Library etc. (which I downvoted) but goes back town to a very old requirement that is kept around for simplicity reason AND compatibility. This is the the reason any UI thread is to be market as sintgle threaded appartement.

Also note that multi threaded drawing, if you implement it yourself, has serious implications. Which one wins optically (stays in the foreground)? This is no really determinable when using multi threaded. You are free to try it, though.

In this case:

  • Having your own buffer and synchronization is a must. Stay away from any windows level graphics library (WPF or Winforms) except for the last step (rawing your bitmap).

  • DirectX 11 supposedly has some support for multi thread calls, but I am unsure how far that goes.

TomTom
I actually had drawing routines on another thread that drew on a buffer, and drew that buffer on the UI thread with DrawImageUnscaled(), and I was even using GDI+ (on the drawing threads), since it's performance is ok - my concern is with percieved performance more than actual performance (e.g., having a 100% responsive UI all times, even while the "background" is drawn, since there are overlays to that buffer that could make the user think the application is more responsive than it actually is, much like what a cursor does, never freezing).
Camilo Martin
Yes, that works - because for windows the drawing is not coming from another thread ;)
TomTom