I see in documentation and several other places that the Mono System.Collections.ObjectModel.ObservableCollection<T> is "not thread-safe". I understand that means I shouldn't allow my application to call methods like Add() from multiple threads at the same time. But I'm curious if this means it has thread affinity, like Views.
I did WPF work a long time ago, and I remember it had thread affinity in WPF, going so far as throwing a specific exception without getting as far as raising its event. But I've also noticed Xamarin Forms seems to automatically transfer VM property changes to the UI thread when I update bindings, and I don't think WPF did that.
So I set up an example Xamarin.Forms project and bound a ListView to an ObservableCollection. I wrote some code to add some items on the UI thread, and some code to add them on a worker thread. For comparison, I also wrote a method that sets a Label's text from a worker thread. Both ways to update the ObservableCollection work. Tapping the button that updates the Label crashes the application.
That would seem to prove there's no thread affinity, and that Xamarin Forms binding handles the event on the correct thread. But I'm also used to thread affinity problems being somewhat unpredictable, so I could just be "getting lucky".
Is there any definitive answer? Can I update a bound ObservableCollection from any thread, so long as I'm mindful of the separate synchronization issue?
Mono ObservableCollection is not thread safe, but has no thread-affinity and shouldn't crash if accessed in a non-concurrent manner, from different threads.
Related
The Problem:
I am trying to have a DataGridView show data that is from a DataTable created and managed by another thread. This thread raises an event to notify the UI thread to update the DGV.
When I try to update it with the UI thread, the UI thread takes ownership of the DataTable, so then when the other thread tries to add another entry I get a cross-thread operations error.
I've been reading up on delegates and how to accomplish this but the problem is that since I want to bind an object from one thread to another, no matter which thread access' the UpdateTable sub, its working with an 1 object it doesn't own.
...
Things I have tried:
I've tried using delegates, however I am new to multithreading apps so I'm struggling to understand what I am doing, I've been making tons of small changes and seeing what happens when I step through debugging.
I've tried to create copies of the data with the UI thread and then bind the DGV to that, but accessing the data in any way from the UI thread locks out the other thread.
Any help on this would be much appreciated. I've been googling and digging through forums for a day now and have had no luck.
Solved,
I went the copying data route. When I originally tried I was doing
NewDataTable = OldDataTable
Where NewDataTable is controlled by the UI thread and bound to the DataGridView and OldDataTable is managed by a different thread. This was not actually creating a copy, it was pointing to the old table.
So I did
NewDataTable = OldDataTable.copy()
This solved it. It's not ideal because if the table starts getting large it may suck up time and memory but for my application it will work. I wish I could figure out a more elegant way to do it, but so-be-it.
I am using a background worker for an app that reads through thousands of files and searches for certain text. It's basically to find out what accounts are part of account groups, so I'm searching the entire group directory via a loop in a background worker.
I have delegate subs setup to update label text and to add items to listboxes, and it seems to have cleared up any issues I had about illegal threading. However, I'm not finding specific details about reading through listboxes, for example. So for instance, if I find the account inside of a group but that group has already been added to my listbox, I don't want to add it again or else it will be a duplicate.
My program is working fine - but from what I've read threading doesn't always throw an error right away. I'm trying to avoid rolling my app out and having the error come up sporadically. So my question is: do I need a delegate to READ a listbox too?
Just as a little terminology note: Delegates are merely pointers to other methods and do not provide any thread-safety at all themselves. What you are doing is called invoking methods on the UI thread (or just invoking, for short).
To answer your question: The best practice is to always invoke when accessing UI elements from a background thread. UI elements (controls) should never be accessed from a background thread because the User Interface cannot handle cross-thread calls, since there's a great chance of concurrency (that is, when two threads try to access the same control at the same time).
When the .NET runtime detects a call to a control from another thread than the control was created on it throws an InvalidOperationException. It does this in order to prevent you from doing something that could potentially break the application. This detection works rather good, but it's not perfect.
In some cases the runtime doesn't detect that you're performing an illegal cross-thread call, in which case it will not throw an exception. Your application still works, but that doesn't exclude the fact that there can still be concurrency issues.
For instance, if you were to add or remove items from the ListBox from the UI thread, while at the same time running a heavy loop over the list box items from the background thread then that would cause your application to break and the loop will most likely throw an exception.
To summarize: You can access some control properties without the .NET runtime throwing an InvalidOperationException, but if the property is something that affects the control's behaviour/look/contents then the best practice is to always invoke to avoid any concurrency issues.
I have read a LOT of material about Windows Form projects not supporting MTA. I get it. However, I also have read about Background worker, async/await and BeginInvoke use with such solutions. This and this are just a couple of examples. Here's one that even uses MSMQ. Some of the examples I have reviewed go way back to VB6 days.
I need to augment a Windows Form project with code to interact with a vendor service via API calls that could benefit from async capability. This being 2014, what is the best way to approach this? I use VB NET and have VS 2010 for my development.
Ideally, I would like to create a class library with the logic to interact with the vendor and just return the results to my Windows Form project. Can that be done?
The fact that MTA is not supported doesn't mean that you can't use multiple threads. The MTA model is just one way to use multiple threads, but because it's difficult to implement objects for that model, Windows Form uses the STA model instead.
The important effect of this is just that it means that the main thread in the application takes care of everything that has to do with the user interface. You can start as many threads as you like/need, but whenever anything from those threads needs to be displayed in the user interface, they have to use the Invoke method to let that update be done in the main thread.
There are already asynchronous method in the framework, for example the BeginRead and BeginWrite methods in the System.IO.FileStream class. You can have a look at those for some hints on how asynchronous methods are used in the framework.
If the API is synchronous, you would make asynchronous methods by simply starting a new thread that does the API call and then executes a callback method when it is done. As it's that thread that is waiting for the response, the call doesn't occupy the main thread.
Is there a way around using the Invoke and InvokeRequired methods for objects which were created in other threads? Is there a method which is more direct and less memory intensive? Perhaps a state machine or thread controls?
Am I wasting my time worrying about this method's resource usage?
I'm using this invoke method: http://tech.xster.net/tips/invoke-ui-changes-across-threads-on-vb-net/
I'm using VB.NET in VS 2012
This strongly fits my doctor's usual advice: "if it hurts then don't do it".
There are several .NET patterns that emphasize keeping the threaded code separate from code that needs to run on the UI. BackgroundWorker has been available for a long time, note how its ProgressChanged and RunWorkerCompleted events run on the UI thread. Good place to update UI without having to invoke yourself.
The .NET 4 Task class hands you the TaskScheduler.FromCurrentSynchronizationContext() method. Which is a good way to chain a task that runs on the UI thread, pretty specifically intended to update the UI with the results of previous tasks that run asynchronously. VS2012 provides yet another weapon with the Async and Await keywords. All good ways to avoid writing the code you don't want to write.
My iPad app syncs with an XML feed, running the sync in an NSOperation subclass executed from an NSOperationQueue. As it parses the feed, it calls back to the main thread via performSelectorOnMainThread:withObject:waitUntilDone: to update various parts of the UI, schedule downloads, etc. Some of this is pretty expensive; the UI can sometimes become unresponsive for a second or two as a sync is going on.
To make the UI more responsive, I've removed the use of performSelectorOnMainThread:withObject:waitUntilDone: in favor of direct calls to perform all the sync-related tasks, including updating the UI. So now the sync takes place entirely on the background thread created by the NSOperationQueue. This seems to work pretty well, and the UI is much more responsive during a sync.
However, I'm leery of releasing with it this way. I've seen some mentions in various places that one should only update the UI on the main thread (example with reference to AppKit). But I've been unable to find anything specific on this topic in the documentation.
So how important is it to update the UI on the main thread? Which parts of an app are thread-safe and which are not? Is there perhaps a reference explaining what's safe to execute in an NSOperation and what should be executed only on the main thread in iOS? Am I really doing something unsafe or crash-prone?
It is extremely important that you always update the UI on the main thread. Touching the UI from a background thread can cause all sorts of issues, including corruption of internal state, crashes, or just plain incorrect behavior. Any work that doesn't require touching the UI should go ahead and do on the background thread, but the bits of code that update the UI definitely needs to happen on the main thread.
The Thread Safety Summary in the Threading Programming Guide discusses which Foundation classes are thread-safe and which aren't. The whole summary is worth a skim for quick answers to common questions.
The Thread Programming Guide also has a very brief section on Threads and Your User Interface, where “it is recommended that you receive user-related events and initiate interface updates from your application’s main thread,” and “Some frameworks, such as Cocoa, generally require this behavior.” No cross-reference to a discussion of this Cocoa requirement, but I imagine I'll run across it eventually.
But the upshot is that, according to this document it is important to perform UI updates on the main thread.
Are you sure you need the NSOperation? NSXMLParser.parse and NSURLConnection.start are already asynchronous. If the class that you're parsing updates some model object, and your view controller observes that model object using KVO, you might wind up with simpler, better performing code.
There is further documentation and discussion in a technical note that goes with the ListAdder sample code. It's TN2109: 'simple and reliable threading with NSOperation'. It repeatedly talks about only updating UIKit elements from the main thread and gives examples of correct and incorrect implementations. You might find further references to it by searching 'thread confinement'.