For example, I have a class that fires an event, and 1000 subscribers to that event. Is a single thread used to fire each subscriber delegate one-by-one? Or does .Net use a thread pool to process some or all of the subscriptions in parallel?
As Tigran said, event invocation is serial. Even more if one of the subscribers throws an exception at some point the rest of them will not be triggered.
The easiest way to trigger an event in parallel will be
public event Action Event;
public void Trigger()
{
if (Event != null)
{
var delegates = Event.GetInvocationList();
Parallel.ForEach(delegates, d => d.DynamicInvoke());
}
}
This implementation will suffer from same problem in case of an exception.
As is, event are simple serial invocation. If you want you can run it in async way, but this is an implementation detail.
In short: there is no any built-in parallelization or async of standard .NET events, it's up to you to implement it.
Related
I am developing a WinForms Application.
I created a custom Control (inheriting from Control class). It has its own Eventhandlers to allow the forms to observe some events.
public event EventHandler<TextBoxFilterEventArgs> DataGetFiltered;
My issues came when, inside the control,in some specific situations I perform a call to the registered receivers:
this.Enabled=false;
if (DataGetFiltered != null)
DataGetFiltered(this, new TextBoxFilterEventArgs(itemsFiltered));
this.Enabled=true;
You can see I set the control disabled/enabled before and after the call.
The form containing the control is registering some methods to that event in a async way:
txtFilter.DataGetFiltered += async (s, e) => await txtFilterByDesc_DataGetFiltered(s, e);
private async Task txtFilterByDesc_DataGetFiltered(object sender, TextBoxFilterEventArgs e)
{
await Task.Run(()=>/*some code*/);
}
What happens?
The control calls to the events handlers registered but it continues to run this.Enabled=true;without waiting previous call to finish( but it has been awaited!)
What's going on?
What happens?
After disabling control, your event handling code runs asynchronous delegate.
The delegate ultimately calls Task.Run and offloads some work to a thread pool thread.
Then delegate returns, and control becomes enabled again, but scheduled task still runs in background.
The control is a textbox that i want to get enabled/disabled during the handling of eventhandlers. I have to move that logic to the handler itself?
Short answer: yes.
More detailed answer: while you're using standard .NET event handling pattern, you have to move this logic into event handler. Event doesn't know about handlers implementation. They can be either synchronous, or asynchronous. So, all you can do is to let event handler to manage Enabled property.
Technically, you can invent some sort of asynchronous event handler, but, actually, you shouldn't. .NET developers know, that event delegate is of type EventHandler/EventHandler<T>. Custom event delegate type breaks well-known pattern.
I think it's because your event handler uses await, but your called method doesn't wait for the handler! So, you need to create your own event that returns Task, like the following:
public delegate Task DataGetFiltered(object sender, TextBoxFilterEventArgs e);
public event DataGetFiltered OnDataGetFiltered;
And in the called method:
if (null != this.OnDataGetFiltered)
{
var args = new TextBoxFilterEventArgs(itemsFiltered);
foreach (var handler in this.OnDataGetFiltered.GetInvocationList().Cast<DataGetFiltered>())
{
await handler(this, args);
}
}
Sometimes we want the event publisher's actions post firing to depend on some state set by the event handlers. A common example is an event that takes CancelEventArgs. The event publisher takes action after firing, conditioned on the value of the Cancel property. If the handler is long running, we don't want to block the UI thread (users can be doing other things while they are waiting). But async handlers may return before the state is set, and the publisher will not have the correct value when it needs it. I solved this by simply providing a mutable Task property in the event argument. It's the responsibility of the handler to set its value, and the publisher to await on it after firing. This seems to work fine.
One objection might be that stateful event args are arguably bad practice, unless you assume only one handler. You could use higher-order functions instead of events, and that would handle the objection above by enforcing one "handler".
One thing that I'm not sure about is how async/await deals with multiple awaiters.
Are there any guarantees about in what order the continuations are executed?
Is there going to be a race condition where the rest of the firing might execute before the rest of the event handler?
Answer is yes. This feels like it's going be an issue for nested async methods generally, whenever the caller and callee both have actions after the await.
Is there anything about the way I'm doing it that has any drawbacks I haven't mentioned?
Is there some other well-known or well-accepted best practice for accomplishing the objective that I'm unaware of?
Any ideas about how to deal with the race condition?
Thanks!
class Publisher
{
void RaiseMyEvent()
{
var e = new MyEventArgs();
OnRaiseMyEvent(e);
if (e.Task != null) await e.HandlerTask;
if (e.Cancel)
{
// Do one thing
}
else
{
// Do the other
}
}
}
class Subscriber
{
void MyEventHandler(object sender, CancelEventArgs e)
{
// Notify user to wait on process
e.Task = SomeAsyncMethod();
await e.Task;
e.Cancel = GetOutcome();
// Clear any notification
}
bool GetOutcome() { }
}
Actually we can avoid a race by ensuring that any needed state values in the event args needed by the firing method are set prior to the continuation in the handler:
class Subscriber
{
void MyEventHandler(object sender, CancelEventArgs e)
{
// Notify user to wait on process
e.Task = Task.Run(() =>
{
//Do stuff
e.Cancel = GetOutcome();
}
await e.Task;
// Clear any notification
}
bool GetOutcome() { }
}
Both continuations execute on the UI thread, but we don't care about the order.
Sometimes we want the event publisher's actions post firing to depend on some state set by the event handlers.
I call these "command events", as opposed to "notification events", and cover a few approaches to async command events on my blog.
After quite a bit of experience, I have come to the conclusion that command events are an anti-pattern. Events in .NET are designed as notification events, and making them behave differently is awkward at best. To use the GoF terminology, .NET events are used to implement the Observer design pattern, but these "command events" are actually an implementation of the Template Method design pattern.
Consider this quote about the Template Method design pattern (pg 328):
It's important for template methods to specify which operations are hooks (may be overridden) and which are abstract operations (must be overridden)
That's a good identifying quality of command events! And if you find yourself writing a .NET event that either requires a handler or can't have more than one handler, then it's a good indication that .NET events are probably the wrong solution.
If you have a Template Method situation, then usually some form of this will suffice as a solution:
interface IDetails { Task ProcessAsync(); }
class Subject
{
private IDetails _details { get; }
public Subject(IDetails details) { _details = details; }
async Task SomeMethodAsync()
{
...
if (_details)
await _details.ProcessAsync();
}
}
I need to wait for an event to finish before continuing.
Here is my code:
foreach (KeyValuePair<string, Stream> pair in this.XMLCollection)
{
...
this.eventAggregator.GetEvent<LogToApplicationEvent>().Publish(credentials);
//wait
...
}
Before continuing I need to wait for "login" event to execute complately.
I tried using Task.Factory, but it did not work for me, or I cant use it right...
This code is on presenter, but the event updates the main UI.
//publish
public virtual void Publish(TPayload payload)
{
base.InternalPublish(payload);
}
At least two possible solutions:
BackgroundWorker
Use a BackgroundWorker to execute your code, and use the RunWorkerCompleted event to execute the code that is run after completion.
A BackgroundWorker wraps the event based asynchronous pattern into a very easy to use mechanism, complete with progress reporting and cancellation. See this BackgroundWorker tutorial and this SO answer .
Tasks (.NET 4.0 and above)
Use a Task object, and use the ContinueWith method to define the code that needs to be executed after completion of the first task.
Event Aggregator publishing and subscribing event pattern is synchronous. You need not to worry about it.
So, it won't resume until its subscribers are finished executing its delegates.
Assumption - You are using inbuilt Event Aggregator class provided by Microsoft.
Is there any good practice (pattern) in turning asynchronous calls into synchronous?
I have a third party library who's methods are all asynchronos, to get result of almoust any method you must listen to an event, which will bring some context with it.
basically it looks like:
service.BeginSomething(...);
service.OnBeginSomethingCompleted += ;
what I need is to execute some code after BeginSomething when it is really complete (thus after OnBeginSomethingCompleted is triggered). It is very inconvinient to handle the response in the event.
The only way I could think of is running a Thread.Sleep loop and wait till some field on the form is updated, but it doesn't look like very elegant sollution.
I'm using .net 4.0.
You could subclass the main class and provide a synchronous version of the operation. If subclassing is not an option you could create an extension method. Here is how things might look.
public class Subclass : BaseClass
{
public void Something()
{
using (var complete = new ManualResetEventSlim(false))
{
EventHandler handler = (sender, args) => { complete.Set(); };
base.OnBeginSomethingCompleted += handler;
try
{
base.BeginSomething();
complete.Wait();
}
finally
{
base.OnBeginSomethingCompleted -= handler;
}
}
}
}
Update:
One thing I should have pointed out is that this could be problematic in some cases. Consider this example.
var x = new Subclass();
x.BeginSomething();
x.Something();
It should be obvious that the handler in Something could receive the OnBeginSomethingCompleted event from the previous call to BeginSomething. Make sure you guard against this somehow.
Use a ManualResetEvent. In your sync wrapper create it, then pass it to the service.BeginSomething() call as part of the state object. Immediately after the call, WaitOne() on it, this will block.
In the service.OnBeginSomethingCompleted event extract it from the state object and set it, this will unblock the sync caller.
As other said, if possible you should try to make your own code async. If that won't work, does your third-party library support the standard BeginXXX, EndXXX async pattern? If so, then using the TPL would make things easy for you. Your code will look something like this:
using System.Threading.Tasks;
...
var task = Task<TResult>.Factory.FromAsync(
service.BeginSomething, service.EndSomething, arg1, arg2, ..., null);
task.Wait();
var result = task.Result;
The specific overload you'll want to use will depend on how many parameters you need to pass. You can see the list here.
If BeginSomething() returns an IAsyncResult (like a delegate's .BeginInvoke would do), you can get the WaitHandle from that:
service.OnBeginSomethingCompleted += ;
var asyncResult = service.BeginSomething();
asyncResult.AsyncWaitHandle.WaitOne(); // Blocks until process is complete
By the way, by assigning the event handler after starting the async process, you are introducing a race condition where the async call may complete before the event is registered, causing it to never fire.
You might want to look at Reactive Extensions
With Rx you can wrap that into an 'event' basically - the do something like someClass.SomeEvent.Subscribe(d=>...) to subscribe using usually some lambda expression to handle what you need. Also use ObserveOn to handle it on the GUI thread (see the details, this is just a hint).
Other option is to use async await (which is now available for use with VS 2010).
hope this helps
NOTE: Rx have a native support for async methods and turning them into Rx events with pretty much just one call. Take a look at Observable.FromAsyncPattern FromAsyncPattern
The general trend of modern software development (on Windows platform too) is to run, what is possible asynchroniously.
Actually from Windows8 software design guidelines, if the code runs more then 50ms, it has to be asynchronious.
So I would not suggest to block the thread, but instead benefit from that library and provide to the user with some nice looking animation saying "wait, responce comming", or something like this, or some progress bar.
In short, do not block thread, notify a user about what is going on in app and leave it async.
This solution is similar to Brian Gideon's, but I think a little bit cleaner for what you're trying to do. It uses the Monitor object to cause the calling thread to wait until the Completed event is triggered.
public class SomeClass : BaseClass
{
public void ExecuteSomethingAndWaitTillDone()
{
// Set up the handler to signal when we're done
service.OnBeginSomethingCompleted += OnCompleted;
// Invoke the asynchronous method.
service.BeginSomething(...);
// Now wait until the event occurs
lock (_synchRoot)
{
// This waits until Monitor.Pulse is called
Monitor.Wait(_synchRoot);
}
}
// This handler is called when BeginSomething completes
private void OnCompleted(object source, ...)
{
// Signal to the original thread that it can continue
lock (_synchRoot)
{
// This lets execution continue on the original thread
Monitor.Pulse(_synchRoot);
}
}
private readonly Object _synchRoot = new Object();
}
I am writing a Windows Form application. It has a thread to perform some operation and when the operation found something it has to notify the main form to change a control.
Currently the notification uses the C# event hadling described in the following MSDN page:
http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx
But I am not sure about the delegate. Since in the situation I described above the thread invokes the delegate. Is this a thread safe approach to raise the event?
Is it better to implement Windows Messages (SendMessage) in C# and then implement the message handler in the WindowProc.
Unless you need very fine control over the threading, you can probably use BackgroundWorker instead. It handles all of the cross-thread communication for you. You basically put your background code in its DoWork event handler and then pass data back to the UI thread via its ProgressChanged and RunWorkerCompleted events. The link above has a complete example of how to use it.
But in general, simply adding event handlers and raising events is thread-safe as long as you follow some basic guidelines. However, the event handler will be called on the same thread as the code that raises the event. The event handling code may not be expecting to be called on a background thread so that's where BackgroundWorker comes in handy.
The following is a very basic skeleton of a class that raises an event in a thread-safe way. Whether the code that handles the event is thread-safe is another matter entirely.
class MyClass {
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened(EventArgs e) {
EventHandler handler = SomethingHappened;
if (handler != null) {
handler(this, e);
}
}
public void DoSomething() {
OnSomethingHappened(EventArgs.Empty);
}
}
Try to use InvokeRequired / Invoke on UI controls. It's better to avoid raw windows message queuing.
The delegate approach isn't all that bad, but the problem is that the event invokes the event handlers in the other thread. That foxes your UI update, which needs to be done in the main thread. So you can use InvokeRequired appropriately in the event handler.
void OnStatusMessage(string s)
{
// might be coming from a different thread
if (txtStatus.InvokeRequired)
{
this.BeginInvoke(new MethodInvoker(delegate()
{
OnStatusMessage(s);
}));
}
else
{
StatusBox.Text += s + "\r\n";
StatusBox.SelectionStart = txtStatus.TextLength;
StatusBox.ScrollToCaret();
}
}
This may not be required when using BackgroundWorker as Josh mentioned. But it's useful if you're considering ThreadPool and WaitCallBack(*) to manage threads.
An issue with using Windows messages is that you have to know which window to send messages to, and multiple subscribers is more painful. (For events you just have to += another handler)
I amn't able to post a hyperlink for WaitCallBack because I don't have multi-link pedigree yet.