Why use Invoke on Controls in .net? [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why .NET does not allow cross-thread operations?
Why is only the UI thread allowed to modify the UI?
From what I have understood, the reason .net raises the illegal cross thread calls exception is that the GUI might show indeterministic behaviour.
But isn't this the case with every other object? If two threads work on the same object, depending on the code, the object might be in an indeterministic situation. So why does this exception exist for control elements? Or why is this exception exclusive to control elements.
And how is using invoke going to help? It will still be indeterministic.

Invoke-ing controls on other threads is required because cross-thread calls to Controls are not allowed. For a more complete discussion as to why this restriction exists you should have a read of that link - I'm not going to answer that here, it just is (however be assured that this restriction exists for a good reason).
Calling Invoke helps us because it allows a background thread to "do stuff" on a UI thread - it works because it doesn't directly call the method, rather it sends a Windows message that says "run this when you get the chance to". The UI thread is running a message pump which continuously processes all messages sent to that thread - often these messages are things like "the user clicked on this button", in which case Windows Forms handles this message by raising the Click event on the relevant control. In this case Windows Forms handles the message by running the supplied delegate.
The result is that only 1 thread is modifying / working with the UI controls at any one point in time (the UI thread).
Note that Invoke makes no guarentees as to the order in which delegates will be run. If its important that two delegates being Invoked from two different threads (or even the same thread) be executed in the correct order then thats a different problem.
Aside: We talk about "the UI thread" because most applications have one thread on which all controls are created, however in reality different controls can be created threads - its the thread that the control was created on which process the message. Obviously in order for those messages to be properly processed there must be a message pump running on that thread.

Most types aren't actually thread safe, but can be used from multiple threads so long as only one thread uses them at a time.
UI controls aren't quite the same: they have thread affinity - they can only be safely used on the UI thread.
Part of the reason for this is that the UI thread may want to redraw them at any time, so they've got to be available at any time. Combine that with not wanting to delay the UI thread while it waits for a lock, and also combine it with the desire to avoid even uncontested locking if you can help it (and the UI thread would have to take out a lot of locks if it needed to do this for every access) and you get a simplified model where it's easier just to say that all access must be on the UI thread. I'm sure it would be possible to design a UI framework without thread affinity, but getting it to perform and behave predictably would be tricky.

Invoke is used to make sure you are calling the UI on the correct thread. but this is needed for every .net object. The UI is made to work on a single thread(this is true with WPF and Winforms). Two different threads can access the same object as long as its not at the same time. If it this happens it creates a race case and could end in dead lock

Related

UI freezes when using SystemEvents.UserPreferenceChanged and multiple UI threads

In my C# Windows Forms application there are two threads:
Main Thread (Program.cs)
WorkerClass Thread (STA-Apartment).
When there is long running Task, it freeze/stuck the entire process and No exception or notification fired..it hangs application.
Internally applications doing processing of records only (selection from SQL tables & inserting in Access DB tables)
UI updates will be done using event Action feature.
Find attached snap for stuck process parallel tasks. Seems like threads internally wait for each other and get process blocked. Code related to the SystemEvents.UserPreferenceChanged event is on one of the stacks.
Why does this happen and how can I resolve it?
It deadlocks on a SystemEvents.UserPreferenceChanged event. This is the standard way an app with windows on more than one thread deadlocks. Best way to invoke the deadlock is to press the Windows+L key. You can see this deadlock analyzed in depth in this blog post.
The SystemEvents class is the troublemaker here, it makes an attempt to raise it events on the UI thread of a program. Which is very important, UI isn't thread-safe. Trouble is, you've got two threads that created UI. SystemEvents is incapable of guessing which one is right, it only has 50% odds at it so is doomed to get it wrong. If it initially guessed wrong at which thread in your program is the UI thread, and that thread exited, then it will be 100% wrong.
This makes creating UI on a worker thread exceedingly hazardous of course. It is technically possible, you'll however have to avoid using several controls from the toolbox. They don't handle the UserPreferenceChanged event well when it is raised on the wrong thread. The ones that definitely cause deadlock are DataGridView, NumericUpDown, DomainUpDown, ToolStrip+MenuStrip and the ToolStripItem derived classes. The ones that are iffy (can't analyze the code deep enough) are RichTextBox and ProgressBar. Looks like I ought to put ProgressBar in the first set, judging from your callstacks.
The true cure is to not create UI on a worker thread. It is never necessary, the UI thread of your program is already capable of handling any number of windows.

Performing long running UI changes without blocking the main thread

Is there anyway to run a large number of UI updates without effecting the main thread in a C# winforms application?
I would like to avoid a long delay when a user clicks a specific event (which in my case is many close form calls to dispose of memory)
I know i can use BackgroundWorker to perform lengthy operations in the "do work" event, but the problem is that you cant change any UI in this event (it will cause a cross thread exception) - so i cant put my large number of close form calls here.
And I cant put the close form calls in the "worker completed" event because this is run on the main thread, and will eventually lockup the main thread causing a bad user experience.
I have thought about spawning a thread to handle closes only when the appication session is idle, but not sure if this is going to be a bit messy.
You should use ProgressChanged event of BackgroundWorker to update UI. To enable this feature set WorkerReportsProgress property of your BackgroundWorker instance to true. Then you can update UI many times by sending data from DoWork event handler:
backgroundWorker.ReportProgress(percentage, yourCustomData);
It is recommended to Make Thread-Safe Calls to Windows Forms Controls. Here is the reason:
Access to Windows Forms controls is not inherently thread safe. If you
have two or more threads manipulating the state of a control, it is
possible to force the control into an inconsistent state. Other
thread-related bugs are possible as well, including race conditions
and deadlocks. It is important to ensure that access to your controls
is done in a thread-safe way.
The .NET Framework helps you detect when you are accessing your
controls in a manner that is not thread safe. When you are running
your application in the debugger, and a thread other than the one
which created a control attempts to call that control, the debugger
raises an InvalidOperationException with the message, "Control control
name accessed from a thread other than the thread it was created on."
This exception occurs reliably during debugging and, under some
circumstances, at run time. You are strongly advised to fix this
problem when you see it.
You can disable that exception:
Form.CheckForIllegalCrossThreadCalls = false;
But controls could (and sometime will) stop working.

Why would a control be on a different thread from the one I'm working in?

I'm not (intentionally) using threads in my C# app. In fact my main method has a [STAThread], which I thought meant I'd only be using one thread.
Why then, would I be getting this error message?
Cross-thread operation not valid: Control 'messageLog' accessed from a thread other than the thread it was created on.
There are a couple of types which can cause your code to run on different threads without any explicit call to System.Threading. In particular FileSystemWatcher and BackgroundWorker come to mind. Are you using any of these types?
Also STAThread in no way limits the ability of your process to spawn threads. It instead sets the COM apartment type of the initial application thread.
Marking your main method with [STAThread] does not mean that you cannot spawn additional threads.
You don't really provide any information about what is triggering your code, so I can't be more specific, but any time you execute asynchronous code it will take place on another thread. Doing things like BeginInvoke on a delegate (or, for that matter, most methods that start with Begin--and definitely if they return an IAsyncResult--are async methods) will execute the code (and the callback) on another thread.
If you can provide some more detail about your situation, I can try to give more specific advice.
[STAThread] does not indicate that your application will be single threaded. It only indicates that the application will use threading a manner that allows other threads to execute while a particular thread is waiting for a time-consuming operation to complete.
As to why the cross threading exception is being thrown, a little more context is needed. What type of control is messageLog? What code accesses this control? Are you using any other controls that implicitly use threads (such as a BackgroundWorker)?

What's wrong with calling Invoke, regardless of InvokeRequired?

I've seen the common setup for cross threading access to a GUI control, such as discussed here:
Shortest way to write a thread-safe access method to a windows forms control
All the web hits I found describe a similar thing.
However, why do we need to check InvokeRequired? Can't we just call Invoke directly?
I assume the answer is no, so my real question is 'why'?
From non-UI threads we can't touch the UI - very bad things can happen, since controls have thread affinity. So from a non-UI thread we must (at a minumum) call Invoke or BeginInvoke.
For UI-threads, however - we don't want to call Invoke lots of time; the issue is that if you are already on the UI thread, it still has the unnecessary overhead of sending a message to the form's pump and processing it.
In reality, in most threading code you know you expect a specific method to be called on a non-UI thread, so in those cases, there is no additional overhead: just call Invoke.
If you try to invoke before a window handle is created (for example, when calling form constructor), you will get an InvalidOperationException. So, generally InvokeRequired check is required.
See MSDN for details.
InvokeRequired basically tells you if you're executing on the right thread or not. If you're not on the correct thread, you need to marshal the task to the correct thread otherwise you don't. Hence the need for the check.
The issue is that GUI controls have a requirement that only code executing on the same thread that was used to instantiate the GUI control can access the GUI control. The reasons behind this requirement are tied to the way that Windows is architected. Suffice to say, it would very difficult to change this.
The InvokeRequired checks the identity of the current executing thread against the identity of the instantiating thread. If they are the same, the code can freely interact with the control. If not, the code must marshal the data across from the current thread to the instantiating thread. This is a slow and costly process and is to be avoided if at all possible. Your code will work if you always invoke and it may be that you will not notice the performance hit, but this scenario is going to be increasingly common as multi-core systems come into use. It is best not to create code "knots" that have to be undone later.
One reason I can think of is performence.
If most of the time the calling thread is the same as the creating thread then you'll have some unnessecry overhead.
The Invoke is going to call the code through Delegate and not directly which would be costly.
Its cost effective to call Invoke only when it required. Hence, InvokeRequired is used to find out is the call being made from same thread or another thread?

How do I Yield to the UI thread to update the UI while doing batch processing in a WinForm app?

I have a WinForms app written in C# with .NET 3.5. It runs a lengthy batch process. I want the app to update status of what the batch process is doing. What is the best way to update the UI?
The BackgroundWorker sounds like the object you want.
The quick and dirty way is using Application.DoEvents() But this can cause problems with the order events are handled. So it's not recommended
The problem is probably not that you have to yield to the ui thread but that you do the processing on the ui thread blocking it from handling messages. You can use the backgroundworker component to do the batch processing on a different thread without blocking the UI thread.
Run the lengthy process on a background thread. The background worker class is an easy way of doing this - it provides simple support for sending progress updates and completion events for which the event handlers are called on the correct thread for you. This keeps the code clean and concise.
To display the updates, progress bars or status bar text are two of the most common approaches.
The key thing to remember is if you are doing things on a background thread, you must switch to the UI thread in order to update windows controls etc.
To beef out what people are saying about DoEvents, here's a description of what can happen.
Say you have some form with data on it and your long running event is saving it to the database or generating a report based on it. You start saving or generating the report, and then periodically you call DoEvents so that the screen keeps painting.
Unfortunately the screen isn't just painting, it will also react to user actions. This is because DoEvents stops what you're doing now to process all the windows messages waiting to be processed by your Winforms app. These messages include requests to redraw, as well as any user typing, clicking, etc.
So for example, while you're saving the data, the user can do things like making the app show a modal dialog box that's completely unrelated to the long running task (eg Help->About). Now you're reacting to new user actions inside the already running long running task. DoEvents will return when all the events that were waiting when you called it are finished, and then your long running task will continue.
What if the user doesn't close the modal dialog? Your long running task waits forever until this dialog is closed. If you're committing to a database and holding a transaction, now you're holding a transaction open while the user is having a coffee. Either your transaction times out and you lose your persistence work, or the transaction doesn't time out and you potentially deadlock other users of the DB.
What's happening here is that Application.DoEvents makes your code reentrant. See the wikipedia definition here. Note some points from the top of the article, that for code to be reentrant, it:
Must hold no static (or global) non-constant data.
Must work only on the data provided to it by the caller.
Must not rely on locks to singleton resources.
Must not call non-reentrant computer programs or routines.
It's very unlikely that long running code in a WinForms app is working only on data passed to the method by the caller, doesn't hold static data, holds no locks, and calls only other reentrant methods.
As many people here are saying, DoEvents can lead to some very weird scenarios in code. The bugs it can lead to can be very hard to diagnose, and your user is not likely to tell you "Oh, this might have happened because I clicked this unrelated button while I was waiting for it to save".
Use Backgroundworker, and if you are also trying to update the GUI thread by handling the ProgressChanged event(like, for a ProgressBar), be sure to also set WorkerReportsProgress=true, or the thread that is reporting progress will die the first time it tries to call ReportProgress...
an exception is thrown, but you might not see it unless you have 'when thrown' enabled, and the output will just show that the thread exited.
Use the backgroundworker component to run your batch processing in a seperate thread, this will then not impact on the UI thread.
I want to restate what my previous commenters noted: please avoid DoEvents() whenever possible, as this is almost always a form of "hack" and causes maintenance nightmares.
If you go the BackgroundWorker road (which I suggest), you'll have to deal with cross-threading calls to the UI if you want to call any methods or properties of Controls, as these are thread-affine and must be called only from the thread they were created on. Use Control.Invoke() and/or Control.BeginInvoke() as appropriate.
If you are running in a background/worker thread, you can call Control.Invoke on one of your UI controls to run a delegate in the UI thread.
Control.Invoke is synchronous (Waits until the delegate returns). If you don't want to wait you use .BeginInvoke() to only queue the command.
The returnvalue of .BeginInvoke() allows you to check if the method completed or to wait until it completed.
Application.DoEvents() or possibly run the batch on a separate thread?
DoEvents() was what I was looking for but I've also voted up the backgroundworker answers because that looks like a good solution that I will investigate some more.

Categories

Resources