I have a WPF ListView that is bound to a collection (List<T>). It is currently updated from the current thread which works ok.
I want to move the logic for updating the list into a thread and I see some potential issues regarding thread safety and the binding of the list. Can I be assured that the binding will not be updated unless I call NotifyPropertyChanged? Is NotifyPropertyChanged a blocking call or does it just add it to a message queue; in this instance surely there may be a condition where I tell the ListView the collection updated, but by the time the binding updates I may be modifying the collection in the other thread which will throw an exception or crash the program.
What is the best method for implementing thread safety in such a scenario?
INotifyPropertyChanged is not thread safe, and it does block the calling thread.
Best? That's A good question. I dunno. The bottom line is that, at some time or another, calls must be marshalled onto the UI thread. When do you do this?
You could 1) prepare everything, then deliver it to the UI thread where the UI is then updated. Or, you could 2) implement INotifyPropertyChanged and make the firing of that event always happen on the UI thread, or 3) you could do one of a number of different things.
Usually, however, you would want updates to the UI to happen all at once (not one at a time, as you would get when adding single items to an ObservableCollection, for instance). So it might be advisable to make some thread safe base classes that implement INotifyProperty and CollectionChanged and use these.
There is nothing in the framework that will do this for you, unfortunately.
You can make the collection update from Dispatcher.Invoke to avoid those threading problems:
void ThreadProc()
{
window.Dispatcher.Invoke(() => {
//UpdateList
});
}
Related
A common exception one can get when working with multiple threads in WPF is:
The calling thread cannot access this object because a different thread owns it
What are the options to deal with this properly?
Depending on the situation there are various options:
Accessing a control from another thread
e.g. updating a TextBlock with progress information.
Data Binding:
In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)
There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...
Dispatching:
You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).
e.g.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.
e.g.
void Update()
{
Action action = () => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.
Special cases:
BackgroundWorker
Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)
Timers
In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.
You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.
Accessing an object created on another thread
e.g. loading an image in the background.
If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.
Accessing a data object from another thread
That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.
This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.
That would be several hundred lines of code, for something I "figured out".
But the summary is:
App_OnStartup
generate a background thread
in the callback,
Call
Application.Current.MainWindow.Dispatcher.CheckAccess() - gets the exception
Application.Current.Dispatcher.CheckAccess() does not
I have a udp listener object that communicates through events where the method/callbacks are +='ed in my mainWindow wpf .cs file.
The event handler functions are called with parameters, one being the message I want displayed in a listbox in the mainWindow.cs
Using the information in this thread by H.B. above;
I have added, tested and handled the crossthread in wpf in my eventhandler callback using the following code, but I use a real message not a hard coded one:
listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere")));
UPDATE:
This is better because you can put more things in the anonymous function.
listBox1.Dispatcher.Invoke((Action)delegate
{
listBox1.Items.Add(e.ReaderMessage);
});
I'm wondering what I need to do to make models thread safe in MVVM. Say I had the following class, which is instantiated as a singleton:
public class RunningTotal: INotifyPropertyChange
{
private int _total;
public int Total
{
get { return _total; }
set
{
_total = value;
PropertyChanged("Total");
}
}
...etc...
}
My view model exposes it via a property:
public RunningTotal RunningTotal { get; }
And my view has a textblock bound to it, i.e. {Binding Path=RunningTotal.Total}.
My app has a background thread that periodically updates the value of Total. Assuming nothing else updates Total, what (if anything) should I do to make all this thread-safe?
Now, what if I wanted to do something similar but using a property of type Dictionary<>, or ObservableCollection<>? Which members (add, remove, clear, indexer) are thread-safe? Should I use a ConcurrentDictionary instead?
My app has a background thread that periodically updates the value of Total. Assuming nothing else updates Total, what (if anything) should I do to make all this thread-safe?
For scalar properties, you don't need to do anything special; the PropertyChanged event is automatically marshaled to the UI thread.
Now, what if I wanted to do something similar but using a property of type Dictionary<>, or ObservableCollection<>? Which members (add, remove, clear, indexer) are thread-safe? Should I use a ConcurrentDictionary instead?
No, this is not thread-safe. If you change the content of an ObservableCollection<T> from a background thread, it will break. You need to do it on the UI thread. An easy way to do it is to use a collection that raises its events on the UI thread, like the one described here.
As for Dictionary<TKey, TValue>, it doesn't raise a notification when its content changes, so the UI is not notified anyway.
Say that there are two threads updating Total, and you want to log all changes to _total in the PropertyChanged method. Now there is a race condition in which PropertyChanged can miss a value. This happens when a thread blocks in the middle of calling set_Total. It updates _total but does yet call PropertyChanged. In the meantime, another thread updates _total to another value:
thread1: _total = 4;
thread2: _total = 5;
thread2: PropertyChanged("Total");
thread1: PropertyChanged("Total");
Now, PropertyChanged is never called with the value of 4.
You can solve this by passing the value to the PropertyChanged method, or by using a lock in the setter.
Since you say that you have one thread which updates this property, there is no possibility for a race condition. This is only the case when multiple threads (or processes) update the same thing at the same time.
The model should be written in a thread-safe way just like any code must be; it's up to you to determine whether you are using locks, concurrent containers or anything other to do it. The models are just library code, which (almost) shouldn't know that its functionality is going to be consumed by a MVVM application.
The VMs, however, have to work in the UI thread. This means that typically they cannot rely that the events from model are coming in the UI thread, so they have to marshal the calls or store them in a task queue if the subscribed events are coming not at the UI thread.
So, the VM is the place which should care about thread safety in a specific way, more than the model needs to.
The View code, in turn, can usually live in happy ignorance about all the threading issues: it gets all the messages/calls/events/whatever in the dedicated UI thread, and makes it own calls in the UI thread as well.
Specifically for your case, your code is not the model but VM, right? In this case you have to fire your events in the UI thread, otherwise the View will be unhappy.
This question provides a thread-marshalled version of the ObservableCollection
How do you correctly update a databound datagridview from a background thread
However, you still need to worry about contention between threads, which would require you to lock resources when they are updated, or use something like Interlocked.Increment.
If one thread is updating, and another is reading, there exists the possiblity that a read is done half way through an update (For example, an Int64 is being modified. The first half (32 bits) has been updated in one thread, and before the second half has been updated, the value is read from a second thread. A completely wrong value is read)
This may or may not be a problem depending on what your application is going to do as a result. If the wrong value will be flashed on the GUI for 1 second, then its probably not a big deal, and the performance penalty of the lock can be ignored. If your program is going to take action based on that value, then you probably need to lock it down.
A simple answer is that you need to schedule the property updates in UI Thread through UI Thread's Dispatcher. This will put updates operation in a queue which will not crash the application.
private void handler(object sender, EventArgs e)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate { updates(); });
}
private void updates() { /* real updates go here */ }
Some thing more elaborate that it is actually so simple... When instantiating your viewmodel in your view just pass the dispatcher down in the ctor.
ServerOperationViewmodel ViewModel;
public pgeServerOperations()
{
InitializeComponent();
ViewModel = new ServerOperationViewmodel(Dispatcher);
}
Then in your View model:
Dispatcher UIDispatcher;
public ServerOperationViewmodel(Dispatcher uiDisp)
{
UIDispatcher = uiDisp;
}
And use it like a normal UI dispatcher.
UIDispatcher.Invoke(() =>
{
.......
});
I will admit that I am still fairly new to MVVM, but I don not think this breaks the MVVM motto.
I have a thread safe observable collection replacement which I would like to write a unit test for. To avoid a false positive I'm trying to write a multi-threaded test that proves an object cannot be added to an ObservableCollection<> without failing so I can swap it with mine and watch it go green. I just cannot get this test to fail (using NUnit).
In no particular order I've so far tried:
Creating the collection on a different thread and updating on current
Creating the collection on the current thread and updating on an alternate
Using different threading mechanisms
ThreadStart
Dispatcher
BackgroundWorker
Using different apartment states
All combinations of STA and MTA on the test itself and/or one or both of the threads
Creating a WPF Window to hold the collection and manipulating the Dispatcher frames manually to simulate a runtime environment.
The custom collection itself is working fine in real code so this is now more of an academic exercise than anything; My threading confidence has been shaken :)
You're trying to test something that is not there...
There is no reason for this test to fail, because the ObservableCollection<T> class itself doesn't have thread affinity. It's not thread-safe, but it just means the behavior will be unpredictable if you use it in a multithread scenario without proper locking; there is nothing in ObservableCollection<T> that will explicitly throw an exception if you do this.
However, the CollectionView class does have thread affinity, which is why you can't add items to an ObservableCollection<T> from a different thread if there is a CollectionView attached to it (which happens, for instance, when you bind an ItemsControl to the collection). But it's the CollectionView that throws an exception, not the ObservableCollection<T>...
Take the following code:
var list = new ObservableCollection<string>();
// var view = CollectionViewSource.GetDefaultView(list);
ThreadPool.QueueUserWorkItem(_ => list.Add("foo"));
It executes without throwing an exception, but if you uncomment the line that creates the CollectionView, it will throw a NotSupportedException:
This type of CollectionView does not support changes to its
SourceCollection from a thread different from the Dispatcher thread.
In a multi-threaded WPF application, it is not possible to update an ObservableCollection from a thread other than WPF window thread.
I know there are workarounds, so my question is not how to avoid the "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread" exception.
My question is, why there is such an exception? Why wasn't it possible to allow collection updates from any thread?
Personally, I don't see any reason to block UI update when ObservableCollection is changed from other threads. If two threads (including parallel ones) are accessing the same object, one listening for changes of object properties through events, the other one doing changes, it will always work, at least if locks are used properly. So, what are the reasons?
First...I feel your pain. The Ui thread restriction can be a pain...
Why can't you update a Ui Element from
a thread other than the one it was
created on ?
My question is, why there is such an
exception?
Well in a nutshell, history. Windows has been around a while and the way some parts of the Gui work are embedded in technologies such as COM and the like....so changing it is not trivial...would be very easy to break something. There are many other issues I'm sure...but somebody smarter than me would need to explain them. I believe the WPF team really wanted to remove this restriction and they worked at it pretty hard...in the end I think the number of core OS changes need was unworkable...so they moved on....rats.
Why wasn't it possible to allow
collection updates from any thread?
Is was and is possible... Making something thread-safe always costs some in performance and add complexity. In most cases the application doesn't call for multi thread access. It is important to understand that, for the most part, Microsoft plays by the same rules we do and the same restrictions. If they had made the ObservableCollection thread-safe ...they would have used the same tools we have...locks, monitors, etc. They cannot break the Ui thread rule any more than we can...no magic...same rules.
I know there are workarounds, so my
question is not how to avoid the "This
type of CollectionView does not
support changes to its
SourceCollection from a thread
different from the Dispatcher thread"
exception.
There are no workarounds...There is nothing to workaround. The ObservableCollection is broken..it is just not thread-safe. You must make it, or access to it, thread-safe. This is the same for anything that is not thread-safe...if you need it to be thread-safe then make it so. If you are using threads then you know about locks and such...use them..that is what they are for.
...block UI update when
ObservableCollection is changed from
other threads.... it will always work,
at least if locks are used
properly....
If locks are used properly...Exactly ! Again, Microsoft could have put these locks in but they didn't and for very good reasons. You can put the locks in. Or you use other tactics that will give you thread-safe access....lots of options.
The Task Parallel Library in .net4.0 provides some new tools for solving these problems. Being able to set a context for a task or a thread is particularly useful...
// get the Ui thread context
_uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Action DoInBackground = new Action(() =>
{
/*...In the background...
...process some data for an ObservableCollection...*/
});
Action DoOnUiThread = new Action(() =>
{
/*...On the UI thread...
...read/write data to an ObservableCollection...*/
});
// start the background task
var t1 = Task.Factory.StartNew(() => DoInBackground());
// when t1 is done run t1..on the Ui thread.
var t2 = t1.ContinueWith(t => DoOnUiThread(), _uiScheduler);
Don't think about the thread affinity requirements of Ui Elements as something to work around....it is just the way it works.
C# and .Net have many tools that you can use that make threading a little less of a nightmare. Use them..they can be fun.
I'm going for a smoke.
If your collection is bound to user interface elements, those user interface elements are listening on the CollectionChanged event of the collection, and this event is raised on the thread, on which you are updating the collection.
So the problem is with the user interface elements, which can only be accessed from the thread, on which they were created, and not with the collection itself.
Firstly I know that there are many question and solutions to correct thread marshalling from threads other than background threads. All the questions and solutions I have found have focused on scenarios where the list or business object itself raises an event that the
Windows form can subscribe to and then correctly marshall the update to the main UI thread.
In my case the list of business objects is being updated by a background thread in a seperate layer . I want this list bound to a control on the main thread. Do I really need to expose an event to the UI from the business object list so that the update can be marshalled correctly?. Can I not quietly update the business object list and have these updates propagated to the UI , without somehow having to expose a list changed event to the UI?
EDIT :
My problem is essentially this :The INotifyProperty changed is fired after a property has been changed. A control bound to an object implementing this interface will attempt to update, if the thread causing the event to fire is not the UI thread, we have a problem. So we need to notify the UI thread that we want to update so that update can be handled in a thread safe manner , this means that the background thread updating objects can not simply go about its business, it has to ask permission to update the objects or ask the UI to make the changes to the object on its behalf. This is what I mean by the UI being pulled into handle object updates.
I've posted an option here (including example) on this old usenet post - look for ThreadedBindingList (don't panic - most of the code is setting up the example; the list class is very small); it might help a bit, but IMO you might do better to simply do the UI updates a bit later...
(don't miss the updates lower in the thread)
My experience has been that if you have business objects bound to the UI, any changes made to those objects must implicitly be performed on the UI thread, or you will get a cross-thread exception.
Changing objects from a non-UI thread, when those objects are databound to the UI, is bad news.
See, if you're objects implement binding-friendly patterns (like INotifyPropertyChanged for example,) and you bind one/many of those objects to the UI, and you behind-the-scenes update your object in a manner that causes any of those binding-friendly events to burple up to the UI, your 'object has changed' notification is making it's way to UI code, causing a cross-thread exception.
Update: One way to get around your objects raising the offending events would be to implement some sort of 'STFU' object-level variable that could be set to true when updates are being made to object state from a non-UI thread. Then, in your "OnRaiseMyEvent(...)" method(s) you can check the status of the STFU variable - if true, STFU, otherwise, raise the event.
Update #2: Ah, with the update to the question, here's what I've done in this situation: Pass an ISynchronizeInvoke to your business object's constructor. Then, the business object can handler whether it needs to marshal an event-raise to the UI thread:
public class MyObject {
private ISynchronizeInvoke _Invoker;
public MyObject(ISynchronizeInvoke invoker) {
_Invoker = invoker;
}
private void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler handlers = this.PropertyChanged;
if (handlers != null) {
if (_Invoker.InvokeRequired) {
_Invoker.Invoke(handlers, new PropertyChangedEventArgs(propertyName));
} else {
handlers(new PropertyChangedEventArgs(propertyName);
}
}
}