Multithreaded multicasting and multihandling

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

If I subscribe multiple event handlers to an event, then they are called
sequentially, right? Is there a native way to have them invoked
simultaneously in separate threads, or would I have to build that
functionality myself? (I don't want to reinvent the wheel here.)

MORE IMPORTANTLY: Is there any legitimate way to connect a single event
handler instance to multiple event generators running in separate threads?
If so, how is synchronization handled within the event handler object?
 
Dave Booker said:
If I subscribe multiple event handlers to an event, then they are called
sequentially, right? Is there a native way to have them invoked
simultaneously in separate threads, or would I have to build that
functionality myself? (I don't want to reinvent the wheel here.)

You'd have to build it yourself.
MORE IMPORTANTLY: Is there any legitimate way to connect a single event
handler instance to multiple event generators running in separate threads?

Assuming the events are thread-safe in terms of subscription and
execution, and your event handler is thread-safe in execution,
everything should be fine.
If so, how is synchronization handled within the event handler object?

It's not really - by default the event handler will be called in
whatever thread raises the event.
 
| If I subscribe multiple event handlers to an event, then they are called
| sequentially, right? Is there a native way to have them invoked
| simultaneously in separate threads, or would I have to build that
| functionality myself? (I don't want to reinvent the wheel here.)

TMK, you need to do that yourself. I might just start them on the
threadpool unless you really need all delegates to run on seperate threads,
then you need to create the new threads yourself.

| MORE IMPORTANTLY: Is there any legitimate way to connect a single event
| handler instance to multiple event generators running in separate threads?
| If so, how is synchronization handled within the event handler object?

Not sure I understand.
 
Dave Booker said:
If I subscribe multiple event handlers to an event, then they are called
sequentially, right? Is there a native way to have them invoked
simultaneously in separate threads, or would I have to build that
functionality myself? (I don't want to reinvent the wheel here.)

You'd have to do it yourself. It's fairly easy with
ThreadPool.QueueUserWorkItem() and anonymous delegates.

---8<---
using System;
using System.Threading;

class App
{
delegate void SomeEvent();

static SomeEvent CreateHandler(TimeSpan delay)
{
return delegate
{
Thread.Sleep(delay);
Console.WriteLine("Hello from {0} (delay {1}).",
Thread.CurrentThread.ManagedThreadId,
delay);
};
}

static event SomeEvent _someHandler;

static void Main()
{
// Create some handlers with decreasing delays, so first
// will have largest delay, and later have smaller delays.
for (int i = 1000; i >= 500; i -= 100)
_someHandler +=
CreateHandler(TimeSpan.FromMilliseconds(i));

Console.WriteLine("Calling delegates on this thread...");
foreach (SomeEvent e in _someHandler.GetInvocationList())
e();

Console.WriteLine("Calling delegates in background...");
foreach (SomeEvent e in _someHandler.GetInvocationList())
{
SomeEvent f = e;
ThreadPool.QueueUserWorkItem(delegate { f(); });
}

// Readline to wait for threadpool to finish.
Console.ReadLine();
}
}
--->8---
MORE IMPORTANTLY: Is there any legitimate way to connect a single event
handler instance to multiple event generators running in separate threads?
If so, how is synchronization handled within the event handler object?

It's not thread-safe. The += operator on events which don't have explicit
an add and remove is simply a method call to a method called
add_<yourEventNameHere>, with a body which performs += on the delegate
behind the event. The += operator for delegates is implemented with
Delegate.Combine:

---8<---
myDelegate += MyMethod;
--->8---

Translates roughly to:

---8<---
myDelegate = (MyDelegateType)
Delegate.Combine(myDelegate, new MyDelegateType(MyMethod));
--->8---

As you can see, there's a race condition there for reads on myDelegate. So
you need synchronization to safely set the delegate, and thus the event.

Don't forget that you can use 'add' and 'remove' (similar to 'get' and
'set' for properties) on the event declaration to add implicit locking if
you want.

-- Barry
 
If I subscribe multiple event handlers to an event, then they are called
sequentially, right? Is there a native way to have them invoked
simultaneously in separate threads, or would I have to build that
functionality myself? (I don't want to reinvent the wheel here.)

You'd have to do it yourself. It's fairly easy with
ThreadPool.QueueUserWorkItem() and anonymous delegates.

---8<---
using System;
using System.Threading;

class App
{
delegate void SomeEvent();

static SomeEvent CreateHandler(TimeSpan delay)
{
return delegate
{
Thread.Sleep(delay);
Console.WriteLine("Hello from {0} (delay {1}).",
Thread.CurrentThread.ManagedThreadId,
delay);
};
}

static event SomeEvent _someHandler;

static void Main()
{
// Create some handlers with decreasing delays, so first
// will have largest delay, and later have smaller delays.
for (int i = 1000; i >= 500; i -= 100)
_someHandler +=
CreateHandler(TimeSpan.FromMilliseconds(i));

Console.WriteLine("Calling delegates on this thread...");
foreach (SomeEvent e in _someHandler.GetInvocationList())
e();

Console.WriteLine("Calling delegates in background...");
foreach (SomeEvent e in _someHandler.GetInvocationList())
{
SomeEvent f = e;
ThreadPool.QueueUserWorkItem(delegate { f(); });
}

// Readline to wait for threadpool to finish.
Console.ReadLine();
}
}
--->8---
MORE IMPORTANTLY: Is there any legitimate way to connect a single event
handler instance to multiple event generators running in separate threads?
If so, how is synchronization handled within the event handler object?

It's not thread-safe. The += operator on events which don't have explicit
an add and remove is simply a method call to a method called
add_<yourEventNameHere>, with a body which performs += on the delegate
behind the event. The += operator for delegates is implemented with
Delegate.Combine:

---8<---
myDelegate += MyMethod;
--->8---

Translates roughly to:

---8<---
myDelegate = (MyDelegateType)
Delegate.Combine(myDelegate, new MyDelegateType(MyMethod));
--->8---

As you can see, there's a race condition there for reads on myDelegate. So
you need synchronization to safely set the delegate, and thus the event.

Don't forget that you can use 'add' and 'remove' (similar to 'get' and
'set' for properties) on the event declaration to add implicit locking if
you want.

-- Barry
 
Barry Kelly said:
It's not thread-safe. The += operator on events which don't have explicit
an add and remove is simply a method call to a method called
add_<yourEventNameHere>, with a body which performs += on the delegate
behind the event.

Not true - a field-like event will lock on *something*, according to
the C# spec. In 1.1, it would always be "this" or
typeof(TheTypeInvolved); in 2.0 it can be a hidden object if the
compiler so desires.

(The MS compiler still just makes the add_XXX method synchronized as
far as I've seen; i.e. it locks on "this" or the type.)

How the event is fired is also part of the thread safety aspect - care
is needed to make sure that the most up-to-date version is used, and
that's it's used without the risk of a NullReferenceException, and
without keeping a lock out during the delegate call.
Don't forget that you can use 'add' and 'remove' (similar to 'get' and
'set' for properties) on the event declaration to add implicit locking if
you want.

Indeed, and this is what I'd suggest, as locking on "this" or the type
is a bad idea. See
http://www.pobox.com/~skeet/csharp/threads/lockchoice.shtml
 
Jon Skeet said:
Not true - a field-like event will lock on *something*, according to
the C# spec. In 1.1, it would always be "this" or
typeof(TheTypeInvolved); in 2.0 it can be a hidden object if the
compiler so desires.

(The MS compiler still just makes the add_XXX method synchronized as
far as I've seen; i.e. it locks on "this" or the type.)

You're right. I checked before I posted with Reflector. I checked again,
and I notice I missed the [MethodImpl(MethodImplOptions.Synchronized)]
attribute.

It's slightly odd that C# leaves out Java's synchronized method semantics
(for good reasons, as you mention, IMHO), yet includes it automatically
for event subscription!

-- Barry
 
Back
Top