Correctly notifying all listeners of the system name named manual reset, and then immediately dropping it

I have a system-wide manual reset event that I create by doing the following:

EventWaitHandle notifyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, notifyEventName, out createdEvent); 

Several processes create this event (for example, it is common to them). It is used to notify when something is updated.

I would like to be able to set this event so that all processes waiting for it are signaled, and then immediately reset so that subsequent expectations in the event are blocked.

If i do

 notifyEvent.Set(); notifyEvent.Reset(); 

Sometimes it notifies all listening processes.

If i do

 notifyEvent.Set(); Thread.Sleep(0); notifyEvent.Reset(); 

Additional processes receive a notification (I assumed that this will happen, since the scheduler has the ability to run).

And if I do

 notifyEvent.Set(); Thread.Sleep(100); notifyEvent.Reset(); 

Then everything seems to work fine, and all processes (like ~ 8) get notified sequentially. I do not like using the "magic number" to call sleep.

Is there a better way to notify all listeners about an OS event in other processes that an event has occurred, so that everyone who listens to it during the notification receives an event signal, and then immediately reset the event so that anyone else that goes to listen will to block?

UPDATE: The semaphore does not seem to be very good here, as the number of listeners for the event may change over time. It is not known in advance how many listeners will be there when you even need to be informed about it.

+6
multithreading c # windows events
source share
3 answers

You are using the EventWaitHandle class incorrectly. The reset event should not be used to signal multiple threads. Instead, you need to create a reset event for each thread, and then when you are ready to fire them, use Set (). The main thread should not call the Reset () method. Each thread must be responsible for closing the gate behind them, so to speak.

Here is a basic example:

 static class Program { static void Main() { List<ThreadState> states = new List<ThreadState>(); ThreadState myState; Thread myThread; string data = ""; for (int i = 0; i < 4; i++) { myThread = new Thread(Work); myState = new ThreadState(); myState.gate = new EventWaitHandle(false, EventResetMode.ManualReset); myState.running = true; myState.index = i + 1; states.Add(myState); myThread.Start(myState); } Console.WriteLine("Enter q to quit."); while (data != "q") { data = Console.ReadLine(); if (data != "q") foreach (ThreadState state in states) state.gate.Set(); } foreach (ThreadState state in states) { state.running = false; state.gate.Set(); } Console.WriteLine("Press any key to quit."); Console.ReadKey(); } static void Work(Object param) { ThreadState state = (ThreadState)param; while (state.running) { Console.WriteLine("Thread #" + state.index + " waiting..."); state.gate.WaitOne(); Console.WriteLine("Thread #" + state.index + " gate opened."); state.gate.Reset(); Console.WriteLine("Thread #" + state.index + " gate closed."); } Console.WriteLine("Thread #" + state.index + " terminating."); } private class ThreadState { public int index; public EventWaitHandle gate; public bool running; } } 
+2
source share

I had the same problem, and surprisingly no good solution was found on the Internet for this case with unrelated / fireman and forgotten / multiple listening, so this is what I came up with.

Please note that the timeout solution between Set() and Reset() calls also has problems with the race state (besides the fact that it depends on an arbitrary timeout value): if the publisher is killed between these calls, then all listeners will see the event as set forever (unless the publisher works again).

So this is the requirement:

  • there is one publisher (although it does not apply in code)
  • there can be any number of listeners (in the same process or in other processes), between 0 and N (N is fixed after binary files are compiled).
  • listeners can come and go as they want without violating the publisher.
  • the publisher can come and go as he wants without disturbing the audience.

The trick is to use AutoReset events, since they do not have problems with race conditions, but define one per listener. We do not know the number of listeners in advance, but we can fix the 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 for 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 receive an event notification:

 ... 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"); } 
+3
source share

The wrong type of synchronization is used here. Instead of an event, you should use the Semaphore class with the number of concurrent accesses you want to allow.

You may also want to have two Semaphores, the second is the code that triggers the event to check (on which the code responsible for the event will contain locks) if you do not want to have two events in quick succession and have one section of code at the tails of another event .

0
source share

All Articles