I'm trying to make some sense out of an application Ive been handed in order to track down the source of an error. Theres a bit of code (simplified here) which creates four threads which in turn populate list views on the main form. Each method gets data from the database and retrieves graphics from a resource dll in order to directly populate an imagelist and listview.
From what Ive read on here (link) updating UI elements from any thread other than the UI thread should not be done, and yet this appears to work?
Thread t0 = new Thread(new ThreadStart(PopulateListView1));
t0.IsBackground = true;
t0.Start();
Thread t1 = new Thread(new ThreadStart(PopulateListView2));
t1.Start();
Thread t2 = new Thread(new ThreadStart(PopulateListView3));
t2.Start();
Thread t3 = new Thread(new ThreadStart(PopulateListView4));
t3.Start();
The error itself is a System.InvalidOperationException "Image cannot be added to the ImageList." which has me wondering if the above code is linked in some way.
Iis this method of populating the UI recommended and if not what are the possible complications resulting from it?
Update:
I may have given some misinformation by referring to a 'form'. The application is a windows forms application but the code is from a plugin application based on a usercontrol. The threads are created inside an initialise method publically exposed by this control. The listviews etc are also part of this plugin usercontrol.
DO NOT USE threads for that - if you have to do that async, use WOrkItems on a THreadPool. Thread usage in general should be reseved for long running items - a THreadPool or the new .NET 4.0 tasks API are way better suited for that.
UI elements should only be namipulated from the element creation thread. It "works" or not depending on what version of the .net framework you use or what the control really is if you break this.
Within your threads methods, such as DoWork() for the BackgroundWorker class, for example, you will need to instiate a delegate method to populate your UI control. Then, verifying whether your UI control requires to be invoked (InvokeRequired property), then invoking it when it'srequired to.
private delegate IList<MyObject> PopulateUiControl();
private void myThread_DoWork(object sender, DoWorkEventArgs e) {
PopulateUiControl myDelegate = FillUiControl;
while(uiControl.InvokeRequired)
uiControl.Invoke(myDelegate);
}
private IList<MyObject> FillUiControl() {
uiControl.Items = myThreadResultsITems;
}
It is not a precise working code, as I can't take the time to do the research, etc. but this shall put you in the path to succeed.
In the end, I agree with the others, try to avoid such things in the future, as it can get tricky to debug or reveal some strange behaviour. Perhaps .NET 4 has some improvements on the topic as Microsoft has worked hard to make parallelism easy for the use of multicore processors for developers.
As others have stated, you cannot update your UI from any thread other than the one it was created by.
If a thread wants to update the UI, it needs to invoke a method on the UI control on the same thread that created it using BeginInvoke.
PS: I am assuming when you say UI, you mean a WindowsForms and not WPF. I have used the above solution successfully in WinForms.
Update: Here are a couple of articles that explain the concept in-depth:
* Threading in Windows Forms
* WinForms UI Thread Invokes: An In-Depth Review of Invoke/BeginInvoke/InvokeRequred
Also, related question from SO: In WinForms, why can't you update UI controls from other threads?
Never update UI from a worker thread. Program may work sometimes, but this is undefined behavior. Add this line to the program initialization code:
Control.CheckForIllegalCrossThreadCalls = true;
After this every incorrect UI update attempt fails, allowing to fix all errors in the code.
If this is done because getting the values fr the listviews takes time, then get the values in a background worker and then use the main thread to bind the data to the listview.
Related
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.
I have a console app that I'm porting to WPF. The application has 3 worker threads, that are all joined to the main thread before some output results are printed to the screen. My understanding is that, if I try and do the same thing in a WPF application, the GUI will be blocked and will not be reponsive to the user. How then can I notify the parent thread that all the threads have completed their work? I think the solution is going to involve delegates and events (or maybe BackgroundWorker?), but it was not clear to me how to get the callback invoked when the thread terminated.
Original Code:
foreach (Thread t in threadList)
{
t.Start();
}
foreach (Thread t in threadList)
{
t.Join();
}
// print some results here
If you are using three BackgroundWorkers, you can use the event RunWorkerCompleted to notice that one of the workers is completed: Before starting the workers set a counter to 3 then decrement and check this counter in the method called by RunWorkerCompleted if it hits 0 you are finished.
You should use three BackgroundWorkers.
You can then handle their RunWorkerCompleted events to find out when the operations finish.
Take a look at this article in MSDN magazine that gives you an example on using BackgroundWorker. Start at Figure 7.
Depends on what you would like to accomplish. What form of communication are you trying to facilitate?
If I were to guess, what you really want is to simply report [or display] your worker results in your application. If this is the case, then in a typical WPF application you have a view model, say
public class AwesomeViewModel : INotifyPropertyChanged
{
// if small fixed number, otherwise, you could use
// an ObservableCollection<T>
public string WorkerResultA { ... }
public string WorkerResultB { ... }
public string WorkerResultC { ... }
}
which is data-bound to your WPF controls. You can simply pass a reference of your view model to each worker thread and they update the class without requiring blocking\waiting on Gui thread. In this manner, each worker reports its results when it completes without intervention from anyone else. This is optimal.
Of course, if you go ahead and do just this, you run into another completely different issue. Which, fyi, is resolvable via Dispatcher. One possible solution here.
As for BackgroundWorker versus explicit Thread control, that is up to you. There are advantages to both, but remember you already have functional code written. That, and in my personal opinion, BackgroundWorker isn't particularly useful.
If you really absolutely positively must implement a more sophisticated synchronization model, then I highly recommend you brush up on ManualResetEvent its cousin AutoResetEvent, Semaphore, keyword lock and concurrent programming in general. Sorry, no shortcuts there :)
Hope this helps!
If you just want to poll the worker threads, you could use something like
bool threadWasDone = thread.Join(0);
Is BackgroundWorker in c# Thread Safe?
The reason I ask this is because I get a
Controls created on one thread cannot
be parented to a control on a
different thread
exception with it. This is my DoWork event code:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var openFile = document.Open(MyFileName);
e.Result = openFile;
}
where document is an UI control that is initialized when the parent form is created. During Open method various properties in document will be filled.
I tried to change the code to invoke, yet the same problem persists. i.e,
document.GetType().GetMethod("Open)".Invoke(document, new object[]{MyFileName})
will yield the same error as the above.
Any idea how to manipulate the document control? In other words, how to make the above code work?
Edit: It was suggested that I use Control.Invoke, but it still didn't work ( both of the threads hanged). This is the code I tried:
private delegate bool OpenFile(string filePath);
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
OpenFile oF = new OpenFile(document.Open);
var openFile = Invoke(oF, MyFileName); // it doesn't really matter whether I use BeginInvoke or Invoke, or other Control.Invoke, the end result is the same. Both the main thread hosting the document and the thread that launches the UI hanged.
e.Result = openFile;
}
It isn't the thread that's the problem it's the fact that it's trying to call a method on a UI control. In both WPF and WinForms controls can only be called on the UI thread (of which there is typically one). You don't say which you are using but you need to call the Control.Invoke method for WinForms or Dispatcher.Invoke for WPF.
The Invoke() reflection method you show will actually invoke the method on the current thread.
You can either invoke as Mehrdad Afshari suggested, or you can make use of the bgw's progress event which comes back on the UI thread. Or the work completed event which also comes back on the UI thread. The difference between the two is WorkCompleted is fired only once at the end. Progress is fired by you from DoWork.
While it's unclear to me what you exactly mean by thread-safety of a BackgroundWorker, the problem is not that object; Windows Forms controls are designed to be manipulated on a single thread (the UI thread). You should not manipulate Windows Forms objects on different threads. You can invoke actions in the UI thread from other threads by using the Control.Invoke method (the Invoke method you are currently using is provided by reflection and is totally unrelated to this problem):
Invoke(new Action(MethodToRunInUIThread));
void MethodToRunInUIThread() {
// do stuff here.
}
By the way, it doesn't make sense to use a background worker if all you are doing is manipulating UI objects.
If that functionality of the UI Control takes that long to execute, there may not be much you can do. "Freezing" occurs when a long-running operation happens on the UI thread, and if that function of the control was not specifically made thread-safe, it must be run on the main thread.
Normally, you'd want to separate the "document" functionality away from the control that displays it. This way, your document could be loaded on a separate, independent thread and be displayed later when ready. Otherwise, the control itself would have to implement a multi-threaded load routine to slow loading freezes.
Since you've specified this is a third party control in your comments, you may be out of luck here.
BackgroundWorker is a thread based structure. The thread-safety matter is about functions when doing simultaneous tasks. Maybe what you ask for is about winforms controls which are accessed through a unique thread, that of the user interface thread.
You need to use Control.BeginInvoke() in DoWork. This executes the delegate asynchronously and so will ensure the calling thread will not "hang".
Control.Invoke() will execute the delegate on the other thread also, but will cause the calling thread to wait for it to complete.
Generally in Windows Forms you are better off using Control.BeginInvoke() wherever possible to help avoid deadlocking between threads that can occur when one thread waits for another, as with Control.Invoke().
If the "document" object inherits from System.Windows.Forms.Control, you can simply call document.BeginInvoke(myDelegate).
However if it is actually some other component that encapsulates GUI controls, it may expose some way to call BeginInvoke. Check the documentation (if any). If there is no such ability, then unfortunately it is probably just not designed to support multi-threaded applications.
It looks like you are confused about the various Invoke/BeginInvoke types (understandable). This earlier question: What is the difference between Invoke and BeginInvoke? and Jon Skeets answer should help clarify things.
#Graviton, a related task with an answer is found here. The person was using BackgroundWorker to update a textbox, same concept applies (yours is only a single worker thread).
If I have Thread A which is the main Application Thread and a secondary Thread. How can I check if a function is being called within Thread B?
Basically I am trying to implement the following code snippit:
public void ensureRunningOnCorrectThread()
{
if( function is being called within ThreadB )
{
performIO()
}
else
{
// call performIO so that it is called (invoked?) on ThreadB
}
}
Is there a way to perform this functionality within C# or is there a better way of looking at the problem?
EDIT 1
I have noticed the following within the MSDN documentation, although Im a dit dubious as to whether or not its a good thing to be doing! :
// if function is being called within ThreadB
if( System.Threading.Thread.CurrentThread.Equals(ThreadB) )
{
}
EDIT 2
I realise that Im looking at this problem in the wrong way (thanks to the answers below who helped me see this) all I care about is that the IO does not happen on ThreadA. This means that it could happen on ThreadB or indeed anyother Thread e.g. a BackgroundWorker. I have decided that creating a new BackgroundWorker within the else portion of the above f statement ensures that the IO is performed in a non-blocking fashion. Im not entirely sure that this is the best solution to my problem, however it appears to work!
Here's one way to do it:
if (System.Threading.Thread.CurrentThread.ManagedThreadId == ThreadB.ManagedThreadId)
...
I don't know enough about .NET's Thread class implementation to know if the comparison above is equivalent to Equals() or not, but in absence of this knowledge, comparing the IDs is a safe bet.
There may be a better (where better = easier, faster, etc.) way to accomplish what you're trying to do, depending on a few things like:
what kind of app (ASP.NET, WinForms, console, etc.) are you building?
why do you want to enforce I/O on only one thread?
what kind of I/O is this? (e.g. writes to one file? network I/O constrained to one socket? etc.)
what are your performance constraints relative to cost of locking, number of concurrent worker threads, etc?
whether the "else" clause in your code needs to be blocking, fire-and-forget, or something more sophisticated
how you want to deal with timeouts, deadlocks, etc.
Adding this info to your question would be helpful, although if yours is a WinForms app and you're talking about user-facing GUI I/O, you can skip the other questions since the scenario is obvious.
Keep in mind that // call performIO so that it is called (invoked?) on ThreadB implementation will vary depending on whether this is WinForms, ASP.NET, console, etc.
If WinForms, check out this CodeProject post for a cool way to handle it. Also see MSDN for how this is usually handled using InvokeRequired.
If Console or generalized server app (no GUI), you'll need to figure out how to let the main thread know that it has work waiting-- and you may want to consider an alternate implementation which has a I/O worker thread or thread pool which just sits around executing queued I/O requests that you queue to it. Or you might want to consider synchronizing your I/O requests (easier) instead of marshalling calls over to one thread (harder).
If ASP.NET, you're probably implementing this in the wrong way. It's usually more effective to use ASP.NET async pages and/or to (per above) synchronize snchronizing to your I/O using lock{} or another synchronization method.
What you are trying to do is the opposite of what the InvokeRequired property of a windows form control does, so if it's a window form application, you could just use the property of your main form:
if (InvokeRequired) {
// running in a separate thread
} else {
// running in the main thread, so needs to send the task to the worker thread
}
The else part of your snippet, Invoking PerformIO on ThreadB is only going to work when ThreadB is the Main thread running a Messageloop.
So maybe you should rethink what you are doing here, it is not a normal construction.
Does your secondary thread do anything else besides the performIO() function? If not, then an easy way to do this is to use a System.Threading.ManualResetEvent. Have the secondary thread sit in a while loop waiting for the event to be set. When the event is signaled, the secondary thread can perform the I/O processing. To signal the event, have the main thread call the Set() method of the event object.
using System.Threading;
static void Main(string[] args)
{
ManualResetEvent processEvent = new ManualResetEvent(false);
Thread thread = new Thread(delegate() {
while (processEvent.WaitOne()) {
performIO();
processEvent.Reset(); // reset for next pass...
}
});
thread.Name = "I/O Processing Thread"; // name the thread
thread.Start();
// Do GUI stuff...
// When time to perform the IO processing, signal the event.
processEvent.Set();
}
Also, as an aside, get into the habit of naming any System.Threading.Thread objects as they are created. When you create the secondary thread, set the thread name via the Name property. This will help you when looking at the Threads window in Debug sessions, and it also allows you to print the thread name to the console or the Output window if the thread identity is ever in doubt.
I know I can start a new worker thread from with .NET. But how do I start a new UI thread (like in MFC)?
I don't mind if the solution is restricted to Windows boxes only; I also would like the solution to be purely .NET - no p/invokes to CreateThread, etc.
Any input appreciated.
Use Application.Run - it starts a message loop in the current thread. There are overloads to take a form to start with, or an application context, or neither. (If you want to do this for a new thread, you need to create the thread and start it in the normal way, and make it call Application.Run.)
If you are interested in using WPF, check out MSDN's article WPF's Threading Model, in particular the "Multiple Windows, Multiple Threads" section. It details what you need to do to create a new Dispatcher and show a window on a new thread.
If you're looking to create a new thread that is capable of creating and dealing with Window handles, then you can use the SetApartmentState function on the Thread object and set it to STA. You'll also likely need to call Application.Run inside the method for this thread in order to create your message loop. However, bear in mind that you're subject to the same cross-threading no-no's that you have in any other thread (ie, you can only interact with the handle for a control on the thread inside which it was created), so you can't do anything on your other UI thread without switching contexts.
Also you can do this:
delegate void MyProcHandler(object param1, object param2);
MyForm.Invoke
(
new MyProcHandler(delegate(object param1, object param2)
{
// some code
}),
null,
null
);