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