Reputation: 1263
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
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.
Invoke
imposes.Invoke
or BeginInvoke
were used from the worker thread.Invoke
.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
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
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