Asynchronous Event Raising

R

rawCoder

Hi all,


How Can You Raise Events Asynchronously ?


Now for the details ...

I want to do inter modular communication using events in such a way that the
contributing modules need not maintain the reference to any module.

For e.g. There is one EventManager class that has event declaration and
public functions that raise events. So any other class that needs to publish
data to interested classes, can call the event raiser method of the
EventManager class. The interested classes would already by handling the
event and will get the notification/data.

Public Class EventManager

Public Shared Event m_Notification()

Public Shared Sub NotificationRaiser()

RaiseEvent m_Notification()

End Sub

End Class


Thats fine and working. Now the problem is that the Event raising mechanism
in .NET is synchronous so in above example the control wont leave the
NotificationRaiser until all classes that handle the notification have done
their task. I would like this to be on separate thread (as much
automatically as possible - dont wanna do the plumbing myself).

So is there any way to raise some event asynchronously (like on some other
thread) without the reference of the class that is handling the event.

I hope I made myself clear, if there are still any queries .. then plz lemme
know.

Any suggestion or reference is welcome.

Thanx
rawCoder
 
R

rawCoder

Just to make myself a lil more clear ....
Want it like it was in Win32 PostMessage ...
Fire And Forget ...
 
N

Nicholas Paldino [.NET/C# MVP]

rawCoder,

If you have a reference to a delegate list (which is what your event is
declared at, ultimately), then all you have to do is call the BeginInvoke
method, and it will be fired on another thread. However, the event handlers
have to code against the fact that the event notification will be on another
thread.

Hope this helps.
 
D

DanGo

BeginInvoke won't work directly because it can only be called on a
delegate with a single subscriber and will throw an exception if you
have multiple subscribers.

Also if you use BeginInvoke you must call EndInvoke.

Take a look at the following AsyncHelper Class.

The AsyncHelper.FireAndForget static method allows you to call a
delegate with a subscriber asynchronously without calling BeginInvoke

The AsyncHelper.FireAsync allows you to call a delegate with multiple
subscribers.

// Based on AsyncHelper by Mike Woodring of
http://staff.develop.com/woodring
//
// Use FireAndForget to execute a method in the thread pool without
having to
// call EndInvoke. Note that the delegate passed to FireAndForget can
only have a
// single Target.
// AsyncHelper.FireAndForget(new MyHandler(MyMethod), methodArg1,
methodArg2, etc);
//
// To Fire an Event asynchronously (with each of the targets being
called on its own thread
// use FireAsync:
// AsyncHelper.FireAsync(MyEvent, eventArg1, eventArg2, ...);
// FireAsync is designed to be called on an event containing zero, one
or more Targets.
// Your FireEvent method does not need to check for null FireAsync will
do it correctly even in a
// multithreaded environment
#region Using Statements
using System;
using System.Reflection;
using System.Threading;
using System.ComponentModel;
#endregion

namespace DanGo.Utilities
{
public class AsyncHelper
{
#region Private Types
// Private class holds data for a delegate to be run on the
thread pool
private class Target
{
#region Private Fields
private readonly Delegate TargetDelegate;
private readonly object[] Args;
#endregion

#region Constructor
/// <summary>
/// Creates a new <see cref="Target"/> instance this holds
arguments and contains
/// the method ExecuteDelegate to be called on the
threadpool.
/// </summary>
/// <param name="d">The users delegate to fire</param>
/// <param name="args">The users arguments to the
delegate</param>
public Target( Delegate d, object[] args)
{
TargetDelegate = d;
Args = args;
}
#endregion

#region Invoker
/// <summary>
/// Executes the delegate by calling DynamicInvoke.
/// </summary>
/// <param name="o">This parameter is required by the
threadpool but is unused.</param>
public void ExecuteDelegate( object o )
{
TargetDelegate.DynamicInvoke(Args);
}
#endregion
}
#endregion

#region Public Static Methods
/// <summary>
/// Fires the delegate without any need to call EndInvoke.
/// </summary>
/// <param name="d">Target Delegate - must contain only one
Target method</param>
/// <param name="args">Users arguments.</param>
public static void FireAndForget( Delegate d, params object[]
args)
{
Target target = new Target(d, args);
ThreadPool.QueueUserWorkItem(new
WaitCallback(target.ExecuteDelegate));
}

/// <summary>
/// Fires each of the members in the delegate asynchronously.
All the members
/// will be fired even if one of them fires an exception
/// </summary>
/// <param name="del">The delegate we want to fire</param>
/// <param name="args">Each of the args we want to
fire.</param>
public static void FireAsync(Delegate del, params object[]
args)
{
// copy the delegate to ensure that we can test for null in
a thread
// safe manner.
Delegate temp = del;
if(temp != null)
{
Delegate[] delegates = temp.GetInvocationList();
foreach(Delegate receiver in delegates)
{
FireAndForget(receiver, args);
}
}
}
#endregion
}
}
 
C

Charles Law

Hi raw (or do you prefer Mr Coder?)

It depends on what your observer classes are doing. If they are updating the
screen, for example, you could use BeginInvoke, which will return
immediately.

Otherwise, your observer could start another thread to process the event,
allowing it to return control straight away. Of course, this becomes more
tricky if another notification event is raised before the first one has been
processed, but perhaps then you can afford to wait.

HTH

Charles
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top