Cross-thread problems with .NET data binding - c#

I have a number of Windows Forms controls which are used to interact with my program objects. Currently they subscribe to an "Updated" event on the object and manually update values when needed. I would like to replace all (or as much as possible) of this boilerplate code using data binding.
The problem I'm running into is that the object state can be modified by any one of several different threads at any moment. Currently I use Invoke() to handle this, which works fine, but when I switch to data binding I get swamped by illegal cross-thread control exceptions. Is there a preferred method to handle this gracefully using data binding, or am I better off just leaving things the way they are now?
Thanks!

If you are data binding your controls to the data sources that are being updated from the underlying thread, then you will have to move the code that does the updating to the UI thread through a call to Invoke.
Or, if you want, you could get a ISynchronizeInvoke implementation (or a SynchronizationContext) and have all the events fire on the UI thread. Of course, this could cause unintended problems with your code, as you weren't firing the events on the UI thread in the first place.

Related

Why only the thread that created UI control can access it [duplicate]

I know that if I am modifying a control from a different thread, I should take care because WinForms and WPF don't allow modifying control's state from other threads.
Why is this restriction in place?
If I can write thread-safe code, I should be able to modify control state safely. Then why is this restriction present?
Several GUI frameworks have this limitation. According to the book Java Concurrency in Practice the reason for this is to avoid complex locking. The problem is that GUI controls may have to react to both events from the UI, data binding and so forth, which leads to locking from several different sources and thus a risk of deadlocks. To avoid this .NET WinForms (and other UIs) restricts access to components to a single thread and thus avoids locking.
In the case of windows, when a control is created UI updates are performed via messages from a message pump. The programmer does not have direct control of the thread the pump is running on, therefore the arrival of a message for a control could possibly result in the changing of the state of the control. If another thread (that the programmer was in direct control of) were allowed to change the state of the control then some sort of synchronization logic would have to be put in place to prevent corruption of the control state. The controls in .Net are not thread safe; this is, I suspect by design. Putting synchronization logic in all controls would be expensive in terms of designing, developing, testing and supporting the code that provides this feature. The programmer could of course provide thread safety to the control for his own code, but not for the code that is in .Net that is running concurrently with his code. One solution to this issue is to restrict these types of actions to one thread and one thread only, which makes the control code in .Net simpler to maintain.
.NET reserves the right to access your control in the thread where you created it at any time. Therefore accesses that come from another thread can never be thread safe.
You might be able to make your own code thread-safe, but there is no way for you to inject the necessary synchronization primitives into the builtin WinForm and WPF code that match up with the ones in your code. Remember, there are a lot of messages getting passed around behind the scenes that eventually cause the UI thread to access the control without you really ever realizing it.
Another interesting aspect of a controls thread affinity is that it could (though I suspect they never would) use the Thread Local Storage pattern. Obviously if you accessed a control on a thread other than the one it was created on it would not be able to access the correct TLS data no matter how carefully you structured the code to guard against all of the normal problems of multithreaded code.
Windows supports many operations which, especially used in combination, are inherently not thread-safe. What should happen, for example, if while one thread is trying to insert some text into a text field starting with the 50th character, while another thread tries to delete the first 40 characters from that field? It would be possible for Windows to use locks to ensure that the second operation couldn't be begun until the first one completed, but using locks would add overhead to every operation, and would also raise the possibility of deadlock if actions on one entity require manipulation of another. Requiring that actions involving a particular window must happen on a particular thread is a more stringent requirement than would be necessary to prevent unsafe combinations of operations from being performed simultaneously, but it's relatively easy to analyze. Using controls from multiple threads and avoiding clashes via some other means would generally be more difficult.
Actually, as far as I know, that WAS the plan from the beginning! Every control could be accessed from any thread! And just because thread locking was needed when another thread required access to the control --and because locking is expensive-- a new threading model was crafted called "thread rental". In that model, related controls would be aggregated into "contexts" using only one thread, thus reducing the amount of locking needed.
Pretty cool, huh?
Unfortunately, that attempt was too bold to succeed (and a bit more complex because locking was still required), so the good old Windows Forms threading model --with the single UI thread and with the creating thread to claim ownership of the control-- is used once again in wPF to make our lives ...easier?

Windows UI Automation: thread blocking when adding event handlers

I am writing a C# program, which uses the UI Automation via Com interop. However, I am having a problem adding/removing an event handler from within another event handler:
My program starts up a new MTA thread, and on that thread, calls AddFocusChangedEventHandler().
I want to monitor for property changes on the focused element. So within the focus-changed handler, I call RemovePropertyChangedEventHandler() on the previously focused element, and AddPropertyChangedEventHandler() on the newly focused element.
However, I find that after about two focus changes, I stop getting either focus-changed, or property-changed, events. My hunch is that something is blocking the background thread.
If I remove the property-changed code, then just the focus tracking works just as expected.
I'm not sure if this is pertenant - but the documentation states that event handlers should be added/removed on the same thread. Since I'm calling AddPropertyChangedEventHandler() in one focus-changed event, and RemovePropertyChangedEventHandler() in another focus-changed event, it's possible that the two calls are being executed on different threads. However, I doubt this to be the case - and even if it were, it shouldn't exhibit the blocking behavior I see. Just mentioning it here for completeness.
There may be multiple problems here. But it's worth noting that after you RemovePropertyChangedEventHandler, you may still get some more events if there are multiple events on the same item (you'll for example get multiple child_added structure changed events if there are multiple children added to an item, it may be similar with multiple properties changing - but not sure). So, if you get multiple events, your code will be called multiple times, probably messing things up.
Another issue is, as you've pointed, you shouldn't subscribe / unsubscribe to events from different threads. But I think this is relevant when there's a chance that these actions are not synchronized - if you're subscribing and unsubscribing to different events (likely in your case) then things will get messy - I'll hazard to say that if you do the subs/unsubs in sequence by some lock mechanism then it should be fine.

Threadsafe observer pattern

I'm writing an application for WPF in MVC pattern. The purpose of application is to display some data in the database and these data are being updated asynchronously.
I'm thinking about how to design the architecture, such that it will be thread-safe. In particular:
Each page (or its viewmodel) must be able to subscribe and unsubscribe from the service, which updates the database.
The service updating the database informs all subscribers, that new data arrived and that they should refresh their views.
Obviously, the page, which is just being closed should unsubscribe from the service and the page, which just appears, should (or may) subscribe.
I could put subscription inside a critical section, as well as broadcast about new data, but then imagine the following scenario (page ~= its viewmodel, that does not matter much here):
Service enters critical section to broadcast information about new data (in separate thread)
Page tries to enter critical section to unsubscribe (in main thread)
Service informs page about new data (in separate thread).
Page populates its fields and raises PropertyChange event (in separate thread).
PropertyChange event is marshalled to the main thread. Which waits for the critical section.
And it looks like a deadlock to me.
How can I safely design this architecture to avoid such deadlocks? Maybe pages should never unsubscribe? Or is there another way to secure threads such that they won't deadlock?
Given that the post is tagged WPF and WP-8.1 and the clarification in the comments, i would do the following:
Have the base Model class (the one with properties holding relevant data) implement INotifyPropertyChanged
Have the Model for ALL pages as ObservableCollection<BaseModel>. The model should also implement a mutex/lock property instantiated in the constructor.
Share the model across all viewmodels (e.g. share the instance of the model).
In the 'Service' performing async operation, i would only lock the section of the code that would Add or Remove items from the Model ObservableCollection using the lock object from the Model itself. This section MUST be placed in the Dispatcher.Invoke() or equivalent platform call. This ensures that it is only UI thread that is waiting to update the collection.
I would bind all the UI in the relevant pages to the model reference in the viewmodel.
This way the UI and viewmodels are careless to the specific service events thus eliminating the overhead of subscribing, and you also limit the duplication of the data if you share the model - even with 20 pages on screen, your service will perform a single update that is propagated to the UI and viewmodels by the powers of the framework (binding).
A simple solution could be: Do not do the unsubscribe operation in the UI thread. (In general do not block the UI thread.) Do it in async way, fire and forget.
Alternatively you may take a look to Rx (Reactive Extensions) what are exactly for this purpose: Implementing the observer pattern in multithreaded way.
Silently "just not unsubscribe" is probably not a good idea. Although I do not know your implementation details, if the event handlers are instance methods, then a reference to that instance implicitly will be kept by the service, and depending the reference chain maybe your page or other instances will be prevented to garbage collected.
"Or is there another way to secure threads such that they won't deadlock?" Currently in .NET framework there is no magic trick what automatically prevents deadlock. Other multithreaded environments may or may not provide an automatic deadlock resolution (note: not prevention) service what can detect a deadlock (after it happen) and automatically choose a victim. In .NET it could be an exception what occurs while your are waiting to a resource. (again this is not implemented yet)

Why does the UI thread hang when updating list in background?

I thought I had a pretty good handle on threading until I came across a scenario in which I wanted to benchmark updates to different grids.
I created a window with a grid control, bound an ObservableCollection to it and populated it with 5000 rows of some complex data type (which contains no locks).
Then I created a task using
Task.Factory.StartNew()
This went through a very tight loop (10 million iterations) updating a random property on a random item in my ObservableCollection, each of which raises an INotifyPropertyChanged event of course.
Now since the updates are all happening on the background thread I expected the UI to update, albeit hard-pressed to keep up with this background thread spinning in a tight loop.
Instead the UI froze for several seconds (but didn't go blank or produce the usual spinning cursor of doom) and then came back once the background thread finished.
My understanding was that the background thread would be taxing a core pretty heavily while producing tons of INPC's, each of which get marshalled automagically by the WPF runtime to the UI thread.
Now the UI thread is doing nothing so I expected it to consume all these INPC's and update the grid but it didn't; not a single update occurred. However, when I do this using a Timer (instead of a tight loop) it works fine.
Would someone please enlighten me as to what the heck the UI thread is doing? Thanks in advance!
If you clog up the message pump with a lot of dispatched updates like this, other messages won't get a chance to be processed, which causes the 'freeze' effect you observe.
One thing that can help here is to use Data Virtualization on your UI control so that only the visible rows are actually bound and listening to INPC updates. This is turned on by default for DataGrid, but if you're using a more custom approach to visualizing the data, this could be an issue.
That said, this won't help with frequent modifications to items that are currently visible, as truly rapid fire updates will still clog up the dispatcher. If you have a use case like this, you probably want to isolate your view model objects a bit and have a way to 'batch' your updates. One technique is to have a way to suppress notification while you do a bunch of updates, then call RaisePropertyChanged(null) (or whatever equivalent method on your INPC helper base class) on each instance to update all bindings to that instance.
Another mechanism is to make the data updates in some other layer (whatever model object(s) your view model instance is representing), then copy over those properties to the view model class at well-defined intervals. For rapidly updating background data, I often use a polling loop rather than triggering on events, simply because the events would occur more frequently than the UI cares about and it slows down the background processing to send all these unnecessary notifications constantly.

Cross-thread event handling on non-UI object

I'm having a problem with handling an event on a different thread from where it is raised. The object that is handling the event is not an UI object however, so I can't use Invoke to execute the delegate and automatically switch to the UI thread for event handling.
The situation is as following: I have an MDI application containing multiple forms. Each form has it's own controller class that handles communication between the coupled form and external objects. All forms are either overview or detail forms (e.g. ContactsOverview & ContactDetail) and share the same data.
In the situation where the error occurs the forms appear in a wizard-like sequence, say a detail form is followed by an overview form. In the detail form data used on the following overview form is changed and before switching to the overview form these changes need to be reflected there. An event is raised from the detail form and handled by the controller for the overview form which does the necessary updating of UI elements.
Now the saving of the changed data in the detail form can take a while so it is necessary that the UI remains responsive and other parts of the application can still be used. This is why a backgroundworker is started to handle this. When the data is saved the event is raised on the background thread. The controller for the overview handles this but when the UI needs to be update there are of course cross-thread exceptions.
So what I need is a way to raise the event on the UI thread, but since the handling doesn't happen on a UI element there's no way to switch threads automatically using Invoke.
From searching around the web I've found one possible solution which is using the producer/consumer pattern. But this would require each controller to listen to a queue of events in a separate thread as far as I understand. Since it's an MDI application there could theoretically be any number of forms with controllers and I don't want to be starting up that many threads.
Any suggestions are welcome. If there would be a way to avoid using the backgroundworker alltogether that would be a suitable solution as well.
Thanks for reading,
Kevin
You can use SynchronizationContext, specifically SynchronizationContext.Current, to post messages to the main synchronization context (which is the main thread for a GUI application).
Unfortunately I don't know enough about the class and its usage to say this is a definite solution. In particular, I don't know what you should do if you don't require the main thread to handle your events, but instead a particular thread.
Perhaps the WindowsFormsSynchronizationContext class can help you out, it has a public parameterless constructor, I'm thinking it might associate it with the current thread, so if you construct that object from the thread that owns the controller, and give it to the background thread code, it might work.
You can have an event on the background objec that the UI element subscribes to. In the event handler (of the subscription - so it is part of the window code) you can then to the invocation. This is how I solve this.
You can try this flag but I don't think it's the best idea, just a work around.
You could also try to instantiate the issuing objects in a non-graphical thread, which may fix your problem.
One more thing, can't you have your UI component handle RunWorkerCompleted (with indirections) ?

Categories