Oxyprogrammer
Oxyprogrammer

Reputation: 1263

Updating UI from Multiple background threads

The issue here is a bit abstract. We all know, for a background thread to update some UI element.

Dispatcher.Invoke()

is the only option (Is it?). However, Dispatcher.Invoke() in itself delegates the update task to the UI thread. Considering scenarios where:

The Dispatcher object would keep on delegating the update task to the UI thread and the UI thread may go slow. What can be a possible solution? How could we solve such an issue in Windows Forms where the threading model was very similar to that of WPF? Does WPF provide any other threading technique?

regards,

Upvotes: 1

Views: 2526

Answers (3)

Brian Gideon
Brian Gideon

Reputation: 48949

Simple, don't use Invoke to update the UI. Instead, have the worker threads publish the data needing "to be sent to the UI thread" into a shared data structure like a queue or a list and have the UI thread poll for it on a specific interval. This has several advantages.

  • It breaks the tight coupling between the UI and worker thread that Invoke imposes.
  • The UI thread gets to dictate when the UI controls get updated...the way it should be when you really think about it.
  • There is no risk of overrunning the UI message queue or starving out other messages as would be the case if Invoke or BeginInvoke were used from the worker thread.
  • The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
  • You get more throughput on both the UI and worker threads.
  • Invoke and BeginInvoke are expensive operations.

I know I harp about this all of the time, but there really are better alternatives to Invoke in many situations. Marshaling techniques like Invoke are way overused.

Upvotes: 1

Akash Kava
Akash Kava

Reputation: 39916

First of all why there is need to update UI that frequent that human eye will not notice, ideally, even if any progress is updated with a gap of a second, it is acceptable. For example if you are writing a file and you are probably writing 4K bytes every 30 milliseconds, human eye will not notice and we dont care about performance on screen in milliseconds.

Not only you will make UI thread busy, but Dispatcher.Invoke will also block your other thread till the execution is finished, Dispatcher.BeginInvoke will not block your other thread.

UI Thread will probably finish updates in few milliseconds if its just updating few labels or progress on screen.

Neither WPF nor any other platform can provide any better way because UI is a very complex and allowing access from multiple threads can lead to deadlocks so often that app may become non-responsive. This is the reason, every platform, be it java, objective-c or any UI framework, will need you to update UI only in UI's creator thread.

However, there is a way in WPF to also create multiple UI threads per window, but its quite complex as well. Games etc use something called double buffering, where they work on one buffer in background in separate thread, while previous buffer is still being updated on screen.

Upvotes: 1

Martin James
Martin James

Reputation: 24847

If you overload the GUI thread input queue by posting messages, (APC's, delegates, whatever), faster than they can be handled, then there will be problems no matter WPF/Forms/whatever.

In those cases where multiple GUI states are so frequently updated that posting every change will overload the queue and/or result in a display that changes too rapidly to be human-readable, it's common for the non-GUI threads to store their latest data in shared object/s and for the GUI thread to display the data using a timer at more reasonable intervals.

If all data must be displayed without loss, (eg. a GUI memo or HTML renderer must display everything sent), then suitable flow-control via object pools and/or lazy-posting of the data might be needed to prevent message-queue overload.

'The issue here is a bit abstract' - not that abstract. I have hit this problem many times with busy apps. In my stuff, prolonged input queue overload tends to result in deadlock because all the objects from my inter-thread comms pool get stuck in posted messages that are not being handled and released to the pool because the GUI is blocked - trying to get an object from the empty pool :((

Upvotes: 2

Related Questions