Raising events asynchronously - c#

I'm looking into options for doing asynchronous event dispatching in a component that has many subscribers to its events. In perusing the options, I ran across this example:
public event ValueChangedEvent ValueChanged;
public void FireEventAsync(EventArgs e)
{
Delegate[] delegates = ValueChanged.GetInvocationList();
foreach (Delegate d in delegates)
{
ValueChangedEvent ev = (ValueChangedEvent)d;
ev.BeginInvoke(e, null, null);
}
}
Beyond the older syntax (the sample was from .NET 1.1), it looks to me like this is a serious resource leak. There's no completion method, no polling for completion, or any other way that EndInvoke will be called.
My understanding is that every BeginInvoke must have a corresponding EndInvoke. Otherwise there are pending AsyncResult object instances floating around, along with (potentially) exceptions that were raised during the asynchronous events.
I realize that it's easy enough to change that by supplying a callback and doing an EndInvoke, but if I don't need to . . .
Handling the asynchronous exeptions is another matter entirely, and, combined with the need to synchronize with the UI thread (i.e. InvokeRequired, etc.) could very well tank the whole idea of doing these asynchronous notifications.
So, two questions:
Am I correct in believing that every BeginInvoke requires a corresponding EndInvoke?
Beyond what I've noted above, are there other pitfalls to doing asynchronous event notifications in Windows Forms applications?

A call to BeginInvoke() should be paired with a EndInvoke() but not doing it will not result in a resource leak. The IAsyncResult returned by BeginInvoke() will be garbage collected.
The biggest pitfall in this code is you are highly exposed to exceptions terminating the application. You might want to wrap the delegate invocation in an exception handler and put some thought into how you want to propagate the exceptions that happen (report the first, produce an aggregate exception, etc).
Invoking a deletage using BeginInvoke() will take a thread off the thread queue to start running the event. This means that the event will always fire off the main UI thread. This might make some event handler scenarios harder to handle (e.g. updating the UI). Handlers would need to realize they need to call SynchronizationContext.Send() or .Post() to synchronize with the primary UI thread. Of course all other multi-thread programming pitfalls also apply.

After thinking about this for a while, I came to the conclusion that it's probably a bad idea to do asynchronous events in Windows Forms controls. Windows Forms events should be raised on the UI thread. Doing otherwise presents an undue burden on clients, and possibly makes a mess with AsyncResult objects and asynchronous exceptions.
It's cleaner to let the clients fire off their own asynchronous processing (using BackgroundWorker or some other technique), or handle the event synchronously.
There are exceptions, of course. System.Timers.Timer, for example, raises the Elapsed event on a thread pool thread. But then, the initial notification comes in on a pool thread. It looks like the general rule is: raise the events on the same thread that got the initial notification. At least, that's the rule that works best for me. That way there's no question about leaking objects.

No. EndInvoke is only required if a return type is specified. Check this out:thread. Also, I posted this thread which is semi related.
I really cant help you with that one! :-) sorry.

Related

Event handlers and multithreading in .NET framework

Can event handlers like FileSystemEventHandler related to FileSystemWatcher class be called from the different threads at the same time (parallel to each other)? Is there any guarantees about it at all?
In general, there are no guarantees.
The event handler runs on the same thread it is invoked on, but that doesn't really tell you anything - for all you know, it could be invoked with something like ThreadPool.QueueUserWorkItem(() => EventHandler()). System.Timers.Timer is one example - the timer callbacks are invoked on a thread pool thread, and multiple can run in parallel.
The major exception are events used in terms of some synchronization context - for example, GUI events (including System.Windows.Forms.Timer) in Windows Forms will only ever launch on the GUI thread. However, the documentation should explicitly specify that the event handlers have some particular thread affinity - it certainly isn't the default assumption.
FileSystemWatcher in particular is even trickier. If it has a SynchronizingObject set, it will have thread affinity - the handlers will be invoked on the synchronizing object. If that synchronizing object is a Form, for example, the handler will always run on the GUI thread and it will never run in parallel. Other synchronizing objects may behave differently (you could always make your own synchronizing object that posts the delegate to the thread pool, for example). Note that the invocation is asynchronous - it does BeginInvoke, not Invoke - so it can very much result in parallel execution if your synchronizing object does something like ThreadPool.QueueUserWorkItem.
If there is no synchronizing object, the handler runs on the same thread that received the notification. Since FileSystemWatcher runs on a IOCP, it's pretty safe to assume that it's just borrowing a threadpool thread for the duration of the callback. However, it also explicitly locks around the whole code, including the event handler invocation - so it will not run in parallel.
The add and remove handlers of the FileSystemWatcher class are nothing special so - as in most cases - it is completely indifferent, from which thread you subscribe a method. If you set the FileSystemWatcher.SynchronizingObject, the delegate will be invoked on that object by a BeginInvoke call; otherwise,
it will be invoked in the tread where your FileSystemWatcher resides.
The methods of a delegate will be called after each other in the thread of the invoker, so there is no syncing issue among them. However, if in your other threads you use common resources with the subscribed methods, you must take care of syncing as usual.

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.

SynchronizationContext.Post(...) in transport event handler

We have a method which, due to threading in the client application requires the usage of SynchronizationContext.
There is a bit of code which one of my colleagues has written which doesnt "feel" right to me, and a performance profiler is telling me that quit a lot of processing is being used in this bit of code.
void transportHelper_SubscriptionMessageReceived(object sender, SubscriptionMessageEventArgs e)
{
if (SynchronizationContext.Current != synchronizationContext)
{
synchronizationContext.Post(delegate
{
transportHelper_SubscriptionMessageReceived(sender, e);
}, null);
return;
}
[code removed....]
}
This just doesnt feel right to me, as we are basically posting the same request to the gui thread event queue...however, I cannot see anyhting oviously problematic either, other than the performance of this area of code.
This method is an event handler attached to an event raised by our middle-tier messaging layer helper (transportHelper) and it exists within a service which handles requests from the GUI.
Does this seem like an acceptable way of making sure that we do not get cross-thread errors? If not, is there a better solution?
Thanks
Let's trace what's going on inside this method, and see what that tells us.
The method signature follows that of event handlers, and as the question indicates, we can expect it to be first called in the context of some thread that is not the UI thread.
The first thing the method does is to compare the SynchronizationContext of the thread it's running in with a SynchronizationContext saved in a member variable. We'll assume the saved context is that of the UI thread. (Mike Peretz posted an excellent series of introductory articles to the SynchronizationContext class on CodeProject)
The method will find the contexts not equal, as it is called in a thread different from the UI thread. The calling thread's context is likely to be null, where the UI thread's context is pretty much guarantied to be set to an instance of WindowsFormsSynchronizationContext. It will then issue a Post() on the UI context, passing a delegate to itself and its arguments, and return immediately. This finishes all processing on the background thread.
The Post() call causes the exact same method to be invoked on the UI thread. Tracing the implementation of WindowsFormsSynchronizationContext.Post() reveals that this is implemented by queueing a custom Windows message on the UI thread's message queue. Arguments are passed, but are not "marshaled", in the sense that they aren't copied or converted.
Our event handler method is now called again, as a result of the Post() call, with the exact same arguments. This time around, however, the thread's SynchronizationContext and the saved context are one and the same. The content of the if clause is skipped, and the [code removed] portion is executed.
Is this a good design? It's hard to say without knowing the content of the [code removed] portion. Here are some thoughts:
Superficially, this doesn't seem to be a horrible design. A message is received on a background thread, and is passed on to the UI thread for presentation. The caller returns immediately to do other things, and the receiver gets to continue with the task. This is somewhat similar to the Unix fork() pattern.
The method is recursive, in a unique way. It doesn't call itself on the same thread. Rather, it causes a different thread to invoke it. As with any recursive piece of code, we would be concerned with its termination condition. From reading the code, it appears reasonably safe to assume that it will always be invoked recursively exactly once, when passed to the UI thread. But it's another issue to be aware of. An alternative design might have passed a different method to Post(), perhaps an anonymous one, and avoid the recursion concern altogether.
There doesn't seem to be an obvious reason for a large amount of processing to occur inside the if clause. Reviewing the WindowsFormsSynchronizationContext implementation of Post() with the .NET reflector reveals some moderately long sequences of code in it, but nothing too fancy; It all happens in RAM, and it does not copy large amounts of data. Essentially it just prepares the arguments and queues a Windows message on the receiving thread's message queue.
You should review what is going on inside the [code removed] portion of the method. Code that touches UI controls totally belongs there -- it must execute inside the UI thread. However, if there is code in there that doesn't deal with UI, it might be a better idea to have it execute in the receiving thread. For example, any CPU-intensive parsing would be better hosted in the receiving thread, where it does not impact the UI responsiveness. You could just move that portion of the code above the if clause, and move the remaining code to a separate method -- to ensure neither portion gets executed twice.
If both the receiving thread and the UI thread need to remain responsive, e.g. both to further incoming message and to user input, you might need to introduce a third thread to process the messages before passing them to the UI thread.

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?

Best way to make events asynchronous in C#

Events are synchronous in C#. I have this application where my main form starts a thread with a loop in it that listens to a stream. When something comes along on the stream an event is fired from the loop to the main form.
If the main form is slow or shows a messagebox or something the loop will be suspended. What is the best way around this? By using a callback and invoke on the main form?
Since you're using a form, the easier way is to use the BackgroundWorker component.
The BackgroundWorker class allows you
to run an operation on a separate,
dedicated thread. Time-consuming
operations like downloads and database
transactions can cause your user
interface (UI) to seem as though it
has stopped responding while they are
running. When you want a responsive UI
and you are faced with long delays
associated with such operations, the
BackgroundWorker class provides a
convenient solution.
Hmmm, I've used different scenarios that depended on what I needed at the time.
I believe the BeginInvoke would probably be the easiest to code since you're almost there. Either way you should be using Invoke already, so just changing to BeginInvoke. Using a callback on a separate thread will accomplish the same thing (as long as you use the threadpool to queue up the callback) as using BeginInvoke.
Events are just delegates, so use BeginInvoke. (see Making Asynchronous Method Calls in the .NET Environment)
You have a few options, as already detailed, but in my experience, you're better off leaving delegates and BeginInvoke, and using BackgroundWorker instead (v2.0+), as it is easier to use and also allows you to interact with the main form on the thread's completion. All in all a very weel implemented solution, I have found.
System.ComponentModel.BackgroundWorker is indeed a good starting point. It will do your asynchronous work, give you notifications of important events, and has ways to better integrate with your forms.
For example, you can activate progress notifications by registering a handler for the ProgressChanged event. (which is highly recommended if you have a long, asynchronous process and you don't want your user to think the application froze)

Categories

Resources