views:

287

answers:

2

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 (e.g. it is shared amongst them). It is used for notifying when something gets updated.

I'd like to be able to set this event so that all of processes waiting on it are signaled and then immediately reset it so that subsequent Waits on the event are blocked.

If I do a

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

It will sometimes notify all listening processes.

If I do a

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

More processes get notified (I assumed this would happen since the scheduler has a chance to run).

And if I do

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

Then everything seems to work out fine and all processes (e.g. ~8) get notified consistently. I don't like the use of a "magic number" for the Sleep call.

Is there a better way to notify all listeners of an OS event in other processes that an event has occurred so that everyone listening to it at the time of notification receive the event signal and then immediately reset the event so that anyone else that goes to listen to the event will block?

UPDATE: A Semaphore doesn't seem to be a good fit here since the number of listeners to the event can vary over time. It is not known in advance how many listeners there will be when an even needs to be notified.

A: 

You are using the wrong synchronization type here. Instead of an event, you should use the Semaphore class, with the number of simultaneous accesses you wish to permit.

You might also want to have two Semaphores, the second one being for the code that fires the event to check (which the code responding to the event would hold locks on) in case you don't want to have two events in quick succession and have one section of code get in on the tails of another event.

casperOne
The notifier doesn't have a way of knowing how many simultaneous accesses there will be. Any of the processes can notify when this event occurs. Additionally the listening processes can come online and offline at any time.
Jeff Moser
I mean, any process can have a thread that notifies that a condition has been updated. For these reasons, it seems like a Semaphore is a good fit (unknown number of listeners that can vary)
Jeff Moser
A: 

You're using the EventWaitHandle class incorrectly. A reset event shouldn't be used to signal multiple threads. Instead, you need to create a reset event for each thread and then when you're ready loop through them all and use Set(). The master thread should not be calling the Reset() method. Each thread should be responsible for closing the gate behind them so to speak.

Here's 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;
    }
}
Spencer Ruport
I'll accept this answer, but it seems that the OS should still let one handle work though :)
Jeff Moser