What are difference between using Invoke and SynchronizationContext.Post object? - c#

When I received an exception that is related with thread context, I use delegate function and I invoke this delegate function. It is necessary for use control from an other thread. But I've just learned that I can use SynchronizationContext.Post() function and I can call my delegate in this method.
I'm not sure which one is better? What are differences between these methods?

It is the same thing, SynchronizationContext.Post() calls BeginInvoke() and Send() calls Invoke().
The key property of SynchronizationContext is that there is more than one implementation of it. Important ones are WindowsFormsSynchronizationContext, it uses Control.Begin/Invoke and DispatcherSynchronizationContext, it uses Dispatcher.Begin/Invoke. There are others for ASP.NET, Windows Store (aka WinRT, aka Universal) apps, out-of-process servers that are COM+ hosted, etcetera.
The extra level of indirection helps avoid taking a dependency on the specific method that invokes. Important for any class library of course.

Control.Invoke is equivalent to SynchronizationContext.Send in that both are synchronous. Control.BeginInvoke is equivalent to SynchronizationContext.Post in that both are asynchronous. Use any of these 4 methods to prevent a cross-thread exception.
Use SynchronizationContext to encapsulate thread marshaling code. For example, Form1 creates object Worker to do some work on a different thread. The constructor for Worker captures the current (i.e. Form1's) SynchronizationContext. When Worker produces data to display on Form1, Worker can use the captured SynchronizationContext to synchronize to Form1's thread before sending a notification, e.g. event, to Form1. This means that Form1 does not need to know about the different thread, does not need to call InvokeRequired, and has less code. It also means that Worker does not need to know that its client is a Form.
Below is an excellent series explaining SynchronizationContext:
Understanding SynchronizationContext - Part I
Understanding SynchronizationContext - Part II
Understanding SynchronizationContext - Part III

Related

Is there a guarantee that AsyncCallbacks will always execute on the main thread?

Exactly what the question says.
I've read the MSDN article given here, and (unless I'm blind), can't see anywhere where it explicity confirms this.
To give more scope, I'm mainly referring to the Socket.Beginxxx methods provided in the Socket class.
Is it safe for me to assume that any AsyncCallbacks will be executed in the main thread? Assume any Socket.Beginxxx methods I call will also be called from the main thread.
EDIT: If this is not the case, should I lock private members of the containing class when I modify them in one of the Socket.Beginxxx AsyncCallbacks? E.g. adding an item to a dictionary?
I've read the MSDN article given here, and (unless I'm blind), can't see anywhere where it explicity confirms this.
The relevant quote is (emphasis added):
Use an AsyncCallback delegate to process the results of an asynchronous operation in a separate thread.
The callback is not guaranteed to execute in the originating thread; in fact, it is guaranteed to run on another thread (i.e., a thread pool thread).
In spite of the other answers, this has absolutely nothing to do with SynchronizationContext or how TAP or EAP work with their contexts. AsyncCallback is part of APM - the oldest asynchronous pattern - which does absolutely no automatic thread marshaling for you.
If this is not the case, should I lock private members of the containing class when I modify them in one of the Socket.Beginxxx AsyncCallbacks? E.g. adding an item to a dictionary?
You could. I have found in my asynchronous socket code that it's easier to marshal all the callbacks back to a single shared thread which is responsible for all socket operations and related data. Then no locks are necessary because all the "completed events" are synchronized to a single thread.
No. Your assumption does not always hold. Some frameworks may override the override the synchronization context to invoke continuations on a specific thread, but there is no guarantee at language-level. Here's what Stephen Toub says about it (in a very informative post on the subject):
frameworks can derive their own context from SynchronizationContext and override the Post method to be more appropriate to the scheduler being represented. In the case of Windows Forms, for example, the WindowsFormsSynchronizationContext implements Post to pass the delegate off to Control.BeginInvoke. For DispatcherSynchronizationContext in WPF, it calls to Dispatcher.BeginInvoke. And so on.... That’s how await “brings you back to where you were.”
With an unchanged SychronizationContext (such as with a console app), the continuations will be queued to the ThreadPool, and so effectively, it could run on any thread.

Capturing the main thread SynchronizationContext or Dispatcher from a library

I have a C# library that would like to have the ability to Send/Post work to the "main" ui thread (if one exists).
This library may be used by:
A winforms application
A native application (with UI)
A console application (with no UI)
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization, that will allow me to (at a later time) Send/Post work to the main thread (if the main thread has that ability--i.e. it has a message pump). For example, the library would like to put up some Winforms UI on the main thread if and only if the main application has the ability for me to get to the main thread.
Things I've tried:
A SynchronizationContext:
Capturing this works fine for a Winforms application (a WindowsFormsSynchronizationContext will be installed as the Current SynchronizationContext. This also works fine for the console app--since I can detect that the Current SynchronizationContext is null (and thus, know that I don't have the ability to send/post work to the main thread). The problem here is the native UI application: It has the ability (i.e. it has a message pump), but the Current Synchronization context is null and thus I can't differentiate it from the Console app case. If I could differentiate, then I could simply install a WindowsFormsSynchronizationContext on the main thread, and I'm good to go.
A Dispatcher: Capturing this using Current creates a new SynchronizationContext. Thus, in all situations I will get back a Dispatcher. However, for a Console app, using Dispatcher.Invoke from a background thread will hang (as expected). I could use Dispatcher.FromThread (which doesn't create a Dispatcher for the thread if one doesn't exist). But the native UI application will return a null Dispatcher using this method, and so then I'm, again, stuck not being able to distinguish the UI application from the console application.
A TaskScheduler: I could use FromCurrentSynchronizationContext. This has the same problems as the SynchronizationContext. I.e. Before calling FromCurrentSyncronizationContext, I'd have to check if the Current SynchronizationContext is null (which will be the case for the Console app and the native ui application). So, again I can't distinguish the native ui application from the console application.
I, of course, could have the user of my library specify whether or not it is a UI application when they call my Initialize method, but I was hoping to avoid that complication for the user of the library if possible.
This is not in general possible, a library that's apt to be used in threads cannot make any assumptions about which particular thread is the UI thread. You can capture Synchronization.Current but that will only work correctly if your initialization method is called from the UI thread. That's not terribly unusual to work out well, like TaskScheduler.FromCurrentSynchronizationContext() tends to work by accident, but not a guarantee. You can add a check, if Thread.CurrentThread.GetApartmentState() doesn't return STA then the odds that you are not being called from the UI thread are very high. SynchronizationContext.Current will also often be null in that case, another way to check.
The (arguably) better ways are to just not worry about it and let the client code figure it out, it won't have any trouble marshaling the callback. Or to expose a property of type SynchronizationContext so that the client code can assign it. Or add it as a constructor argument. Throw an InvalidOperationException if you are ready to Post but find out that it is still null, that's an oversight that the client programmer only makes once.
I think you should make this an option to your Initialize method (or somehow allow your caller to request UI interaction), to me that just makes more sense. I don't know the specifics but these seems to me to be a "courteous" thing to do, let your caller decide if they want you to or want to support your UI. I would take it one step further and even as the caller to supply a synchronization context. But that's my opinion.
To answer your question, there are a few "hacks" you can use to determine if you're running in a console applicaiton. This SO question has some information on that: C#/.NET: Detect whether program is being run as a service or a console application
Change the library initialization to have a SyncronizationContext parameter. If the parameter is null then the library doesn't need to do anything special, if not null Post/Send GUI updates there.
I think this is exactly what AsyncOperationManager.CreateOperation() is for.“Implementing the Event-based Asynchronous Pattern” states:
The Event-based Asynchronous Pattern provides a standardized way to package a class that has asynchronous features. If implemented with helper classes like AsyncOperationManager, your class will work correctly under any application model, including ASP.NET, Console applications, and Windows Forms applications.
It is up to the caller to decide if they want to call your API on the UI thread or not. If they do, this will capture the context and events will go through the message pump in order. In a Console application you can get the same behavior if you install a SynchronizationContext such you get for free by using AsyncContext.Run() from the Nito.AsyncEx nuget package. No need for an extra property or to have to write the conditional code yourself. If no serializing synchronization context is available, AsyncOperation.Post() will use the fake synchronization context available to Console apps which just queue the event to the threadpool instead (meaning that the posts may not execute in order). Just remember to call AsyncOperation.OperationCompleted() or AsyncOperation.PostOperationCompleted() when done.
In the library I'd like to capture something (A SynchronizationContext, a Dispatcher, a Task Scheduler, or something else) during initialization
This is exactly what AsyncOperationManager.CreateOperation() does, and in an environment-agnostic way. But you should try to pair this with a call to OperationCompleted() which maybe would be more difficult given the API you want to expose. The easiest way to use AsyncOperation would be to start an operation when your library actually starts an operation instead of during initialization. Or by having the initialization routine return an IDisposable context object handle which would signal to the consumer that they need to manage its lifetime.

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.

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?

Delegates used in Threads?

What happen internally when we call BeginInvoke on a variable of delegate type?
This depends on the type of object in which you call BeginInvoke.
ISynchronizeInvoke is the interface that defines BeginInvoke. It passes the delegate to the object that implements that interface, and that object will (should) schedule the thread to run on it's own main thread.
There are a few objects that implement this interface. The Dispatcher in WPF does this - when you call BeginInvoke on the dispatcher, the delegate is added to the dispatcher's queue, and run when it is appropriate.
The Control base class in Windows Forms also implements ISynchronizeInvoke (and I believe this may be what your question was hinting at). In Windows Forms, things are much more complicated. Here is a great article explaining the details. Basically, what happens when you call BeginInvoke on a winforms control is that a special marshaller creates a windows message that is passed to the program, and the UI thread queues the delegate to be run. It's a bit more complex than that (as that article describes), but that's the basic idea. The delegate is then run on the main UI thread.
There are other objects that implement ISynchronizeInvoke, but most of them are objects that are managing and running their own thread. These objects maintain a queue of delegates, and add yours to that queue so it runs on their thread.

Categories

Resources