Making use of multiprocessing in WPF


There was a query on the MSDN forums for WPF the other day that asked about leveraging multiple processors in WPF applications.  I responded, and am basically repeating that response here, with a little bit of extension:


WPF 3.0 (and the version coming out with Orcas, 3.5) is definitely an STA(*)-based model, but here are a some observations/comments on how multiple processors can and should be used in WPF applications.


Serialized/Atomic programming model for UI programming is essential:




  • Since time immemorial (i.e. Windows 3.1 ) the way developers have written event-based UI programs has been fairly constant:  register event handlers that are invoked through user interface actions, and have those event handlers modify the UI as well as maintain private state.  There’s a fundamental assumption of, if not single-threadedness, at least atomicity and serialization of operations.  STA definitely provides that.  Rental-thread (**) could provide that as well, and does so in ASP.NET (but without any multicore benefits for a single application).  Free threaded definitely doesn’t provide those guarantees and would result in havoc for UI developers.



  • In fact, we’ve seen such havoc in Windows Forms.  Unlike WPF, where access from a separate thread to UI objects results in explicit exceptions, Windows Forms is looser.  As a result, apps have gotten away, temporarily, with accessing UI objects from separate threads in Windows Forms.  The problem is that it sometimes works, sometimes doesn’t.  It’s one of the most widely reported programming problems with Windows Forms (and one of the motivations for making it more iron-clad in WPF).



  • Thus, we don’t believe that, as long as developers are writing stateful and state-modifying logic for manipulating their UIs (and there’s no sign of that changing), that making the event handlers be free threaded is the right way to go.  However, there are alternative ways to use those cores.


WPF Implementation Use of Multithreading




  • There is a degree of multithreading support built into WPF, with the rendering/composition happening on a second thread from the UI thread.  Thus there’s a natural two-thread division of labor.  However, it doesn’t naturally extend beyond that.



  • While we don’t do so today, we’re definitely interested in subdividing internal computation across cores.  Layout and databinding are both potential examples (though both also have potential pitfalls with invocation of stateful user code).  Rendering can also potentially benefit from multiple cores.  (Though not necessarily as much as one would initially think, since so much of the rendering is typically done on the GPU, which itself is massively parallelized.)  Silverlight’s software renderer, for example, takes great advantage of multiple cores.



  • We’ll be looking into the above in the context of more broadly looking at performance wins that can be had.


Making application operations multithreaded


This leads to the final aspect here:  None of the caveats above should prevent the application itself from being multithreaded.  There’s great support in WPF and in the .NET Framework itself for doing so.  The trick is to be sure that when it comes time to manipulate WPF objects, that that manipulation is done on the UI thread.  Here are some techniques:




  • Use BackgroundWorker.  This component invokes a “DoWork” event on a separate thread, and when that work is completed, raises a completion event back on the UI thread.  Progress notification and cancellation are also supported.



  • The System.Net.WebClient class also provides support for this sort of asynchronous model, where file and data downloads occur asynchronously, but completion is reported back on the UI thread.



  • Web services (both Whidbey “web references” and Orcas “service references”) provide similar asynchronous support in the proxies that are automatically generated by VisualStudio.  They provide methods that follow the general “Asynchronous Pattern For Components” model, which basically means that for a each synchronous web service call named Foo, there will also be a FooAsync() method and a FooCompleted event generated that provide asynchronous invocation of the web service.  FooCompleted will be raised on the UI thread with the results of the web service invocation available in the EventArgs.



  • Use the WPF Dispatcher.  The WPF Dispatcher can be used explicitly for finer-grained control of the message queue being processed by the WPF application.  Other threads can post delegates to be invoked on the UI thread with a high degree of control.



  • Use multiple UI threads driving separate windows.  A somewhat more advanced technique involves creating multiple UI threads each talking to its own Window.  Each UI thread is STA, but if your application is suitably compartmentalized, this can be an effective technique.



  • Use multiple UI threads targeting the same window.  A refinement of the technique above lets you create multiple UI threads, and bring their results together via HostVisual for hosting cross-thread visuals.  Dwayne Need has a great blog post on doing just that.


Anyhow…  hope this helps with some context and ideas.  We think this opens lots of doors for creative use of multiprocessing within WPF applications.  Interested in your experiences with all of this stuff!


(*) STA stands for “Single Threaded Apartment”, which basically means that only the thread that creates a UI object is able to manipulate (i.e., get or set properties, or call methods) it.


(**) Rental-threaded, or RTA (for “Rental Threaded Apartment”), means that any thread can take ownership and manipulate a UI object, but only one can do so at a time.  So operations are guaranteed to be serialized, even if they execute on different threads.

Comments (12)

  1. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  2. Henk de Koning says:

    Although I completely agree with the gist of your post, there’s 3 little things that caught my eye:

    1) STA’s are definitely not atomic. There’s been a lot of work down in the COM era to make sure UI’s would not hang while doing blocking COM calls (out of the apartment). The consequence is that STA’s can be re-entered (on the same thread). What this means is that it is possible for one event handler to call out of the STA and, while being blocked, another event handler fires — modifying the same state;

    2) ‘rental’ sort of changed name to ‘neutral’. Just nagging, I know, but the term neutral apartment will show up in the help a bit more;

    3) as of x-thread synchronization: there’s this pattern introduced in 2.0 that uses System.Threading.SynchronizationContext. I know there’s a DispatcherSynchronizationContext. So, presumably, instead of passing around DependencyObjects, I can pass around an AsyncOperation that wraps my UI handler ?

  3. Niki says:

    "…accessing UI objects from separate threads in Windows Forms.  The problem is that it sometimes works, sometimes doesn’t. "

    Just curious: What specifically didn’t work? I mean, many .NET-Controls are just thin wrappers around native Win32 controls, and those are essentially "thread-safe" because you communicate with them via SendMessage, and SendMessage serializes calls. I never had any problems with accessing UI controls from different threads in Win32 (as long as I’ve synchronized threads properly). I do feel Windows.Forms makes life a little harder in that respect, and I’d like to understand why.

    BTW: STA doesn’t guarantee atomicity; One sure way to break atomicity is to use PeekMessage/GetMessage/TranslateMessage/DispatchMessage-APIs or Application.DoEvents in a message handler. The only reason I know why someone would call Application.DoEvents is to break atomicity.

  4. Greg Schechter says:

    Thanks for the comments about STA’s not being guaranteed to be atomic.  I had forgotten that.  I do think the points still hold regarding the ‘intent’ of event handlers in WPF and other UI frameworks.  Also thanks for the nomenclature clarification of "rental" == "neutral".

    Regarding S.T.SynchronizationContext.  This is what BackgroundWorker, WebClient, and the "Async Pattern for Components" referenced above use in order to dispatch back to the correct thread.  I don’t fully understand, though, the suggestion of passing the AsyncOperation around instead of DependencyObjects.  Can you clarify or give an example?

    Thanks,

    Greg

  5. There was a query on the MSDN forums for WPF the other day that asked about leveraging multiple processors

  6. Yogesh says:

    Making use of multiprocessing in WPF

    and repainting object in wpf

  7. Yogesh says:

    Making use of multiprocessing in WPF

  8. Techniques says:

    Over at Greg Schecter’s Blog, he has a great article on how to implement multi-processing in WPF. Taking

  9. Morbo says:

    Why are MS architects foaming at the mouth to find ways to use multiple cores from within a single process?

    So what if a process is single threaded (or two-threaded, as in WPF)?  There are almost 90 other processes running on my Vista system, right now.  Search indexer… virus scanner.. update downloader.. Windows Defender.. all the SQM and diagnostic/reliability tracking stuff.. firewall.. defragger, and superfetch… and not least, the Shell and DWM processes.

    PLEASE don’t start consuming all my cores from every single processes.  The only way Vista is usable at all, right now, is if you have 2 or more cores — allowing the interactive app to remain responsive while the other cores spin away processing all those background services.

  10. Lexapro. Why does lexapro make me sleep all the time.

  11. Wohoo, hari ini penasaran udah berapa baris kode sih aku tulis: Oh ya, tool Line Counter buatan mas Rich

Skip to main content