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

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?

Related

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

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

BackgroundWorker component in services

I know the BackgroundWorker should not be used in Windows Services but would anyone have a good online reference explaining why?
BackgroundWorker relies on a current SynchronizationContext being set in order to function. It's really intended and designed specifically for working with UI code.
It's typically better in a service to self-manage your threads, since there are no UI synchronization issues. Using the threading API (or .NET 4 Task API) is a much better option here.
Well, it's okayish to use a BGW in a service, it just doesn't do anything especially useful. Its reason for being is its ability to raise the ProgressChanged and RunWorkerCompleted events on a specific thread. Getting code to run on a specific thread is a very non-trivial thing to do. You cannot simply inject a call into the thread while it is executing code. That causes horrible re-entrancy problems. The thread has to be 'idle', in a state where inject code doesn't cause trouble.
Having a thread in an idle state is a fairly unnatural condition. You use threads to run code, not for them to be idly spinning its heels. This is however the way a UI thread works. It spends 99% of its time in the message loop, waiting for Windows to tell it to do something. A button click, a paint request, a keyboard press, that sort of thing. While it is inside the message loop, it is in fact idle. A very good time to execute injected code.
Which is what Winforms' Control.Begin/Invoke and WPF's Dispatcher.Begin/Invoke do. They put a delegate in a queue, the queue is emptied and the delegate targets executed by the message loop. The WindowsFormsSynchronizationContext and DispatcherSynchronizationContext classes are the synchronization providers that uses them. Winforms and WPF replace SynchronizationContext.Current with an instance of them. Which in turn gets used by BGW to raise the events. Which makes them run on the UI thread. Which allows you to update the non thread-safe user interface components from a worker thread.
You can probably see where this is heading, a service uses neither. The default synchronization provider doesn't synchronize anything. It simply uses a threadpool thread to call the Send or Post callback. Which is what will happen when you use BGW in a service. Now there is actually no point at all in having these events. You might as well let the DoWork handler call the event handling methods directly. After all, the thread on which DoWork runs is just another threadpool thread as well.
Well, no real harm done, other than making it quite a bit slower.
I've used BackgroundWorker in windows services many times without any ill effect. While its use of SynchronizationContext may be unnecessary, I haven't observed it causing problems or poor performance.

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)?

Lock a winforms control

I need to ensure that, once the execution hits a method, the control received by this method is not changed by another thread.
Basically, I thought in something like this:
private void doSomeWork(Control control) {
lock (control) {
// do some stuff with the control...
}
}
Is this a bad idea?
Edit:
Actually, what I'm trying to do, is to ensure that the control will not disposed by another thread while I execute some of the control's methods (which, by the way, will be executed via reflection).
In a well behaving application, windows forms controls are already restricted to only one thread. If any thread tries to access a control created in a different thread, an exception will be thrown.
There is nothing wrong about your code, just know that right now it's mostly useless unless you are hacking your way through the protection (which is possible).
Usually, when you have data being created or manipulated in a working thread, the working thread will send an event to the UI thread to update the UI. In no way should a working thread updates the UI itself, it will automatically fail.
Actually Fernando, it's not a bad idea but it's not the correct way to look at locking. You need to closely read what the lock statement does in .Net:
http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx
i think that from your statement you expect the whole object to be locked, or somehow be made safe for threading, because the object iteself is used in a locked block of code. What actually happens is that block of code is locked and not allowed to be executed by two or more threads at the same time. If that block of code is the only place you're going to be operating on the control then you're ok, otherwise you'll need to do synch locks on the object itself.
Don't have a lot of experience working with threads, but, maybe I'll suggest you to start the Form Control in a new thread using an anonymous delegate:
t= new Thread(delegate() {
MyMethodToInvokeTheWinFormControl();
});
t.Start();
It depends entirely on what you mean by "not changed".
If your meaning is "any other thread cannot change this control, at all, in any way", then that's not how lock works.
A lock in this sense is not like a regular lock on a door to a house. It's more like a small yellow post-it note that says "Locked". As long as other threads read the note and abide by what it says, it should be fine, but any other thread that doesn't care about the note at all will of course not be prevented from messing with your control.
In any case, what exactly are you trying to accomplish? You should never be messing with controls from other than the main thread so the problem shouldn't exist in the first place.
Instead you should be marshalling all work on the control onto the main thread through the use of the Invoke method on the control.

what should i avoid doing on background thread in winforms

besides updating GUI controls from background threads, is there any other operations that should avoid being done on background threads in winforms?
Oh, there are plenty of traps. BGW doesn't do much to protect you from the usual hazards of threaded programming. And adds some of its own:
Variables that are accessed from both the BGW and the UI thread must be protected by a lock.
Do not update a bound data source in a BGW. The control updates will be done on the BGW thread but will not generate an exception.
Don't call ReportProgress() too often. Doing it more than about 1000 times per second will freeze the UI thread. About 25 times/sec is enough.
Careful with the userstate argument you can pass to ReportProgress(). It must not be modified by the BGW after the call.
Don't loop on the IsBusy property in the UI thread, it will deadlock.
The BGW thread will be aborted when the main form closes. Watch out for necessary cleanup.
Be sure to inspect the Error property in the RunWorkerCompleted event, it tells you when something went wrong.
This is sort of broad. Don't do anything in a background thread if you don't need to; that is, don't thread out some code just because you feel like it. Use threads where it is appropriate such as for long running tasks that you do not want to interrupt the GUI and so forth. Also, if you end up just calling Application.DoEvents() from your main UI thread just waiting on a task from another thread, you might think about keeping one thread and doing the work in small pieces in a loop where you would repaint the GUI with DoEvents() calls. This is just a suggesiton; however, of course, many times you do need to create multiple threads.
Perhaps you can ask about particular situations?
Well, the reason you should not update GUI controls on a background thread is that the GUI control classes are not threadsafe. So, you can generalize that: don't mess with instances of non-threadsafe classes from a background thread if there is some other thread that might also use them. (That's broad, I know, but anything that breaks that rule could get you in trouble).
But I think the gist of your question is whether or not you've covered all the bases that Control.Invoke() was created to cover. If so, yes, you have ... Control.Invoke was specifically designed for the fact that controls are not threadsafe, and therefore, other threads should only modify controls via Control.Invoke().
I agree with Bobby that your question is too broad. Instead start with the assumption that if you have to create a worker thread, you're not going to put anything in it except what absolutely has to be there to complete the required task.

Categories

Resources