Properly notifying all listeners of a system wide named manual reset event and then immediately resetting it
See the question and my original answer on StackOverflowI had the same problem and surprisingly couldn't find any good solution on the web for this loose-coupled / fire and forget / multiple listeners type of event, so here is what I came up with.
Note the solution with the timeout between Set()
and Reset()
calls has also a race-condition issue (beyond the fact it relies on an arbitrary timeout value): if the publisher gets killed between these calls, then all the listeners will see the event as set forever (unless the publisher gets live again).
So the requirement is:
- there is one publisher (although it's not really enforced in the code)
- there can be any number of listeners (in the same process or in other processes), between 0 and N (N is fixed once the binaries are compiled).
- listeners can come and go as they want without disturbing the publisher
- publisher can come and go as it wants without disturbing the listeners
The trick is to use AutoReset events because they don't have race condition issues, but define one per listener. We don't know the number of listeners beforehand but we can fix a maximum number of listeners ('N' described above):
const int MAX_EVENT_LISTENERS = 10;
const string EVENT_NAME = "myEvent_";
Here is the publisher code to raise the event to all potential listeners:
public static void RaiseEvent()
{
for (int i = 0; i < MAX_EVENT_LISTENERS; i++)
{
EventWaitHandle evt;
if (EventWaitHandle.TryOpenExisting(EVENT_NAME + i, out evt))
{
evt.Set();
evt.Dispose();
}
}
}
Here is the listener code to get notified of the event:
...
EventWaitHandle evt = GetEvent();
do
{
bool b = evt.WaitOne();
// event was set!
}
while (true);
....
// create our own event that no other listener has
public static EventWaitHandle GetEvent()
{
for (int i = 0; i < MAX_EVENT_LISTENERS; i++)
{
bool createdNew;
EventWaitHandle evt = new EventWaitHandle(false, EventResetMode.AutoReset, EVENT_NAME + i, out createdNew);
if (createdNew)
return evt;
evt.Dispose();
}
throw new Exception("Increase MAX_EVENT_LISTENERS");
}