正确通知所有侦听器系统范围内的手动重置事件,然后立即重置它

Jef*_*ser 6 c# windows events multithreading

我有一个系统范围的手动重置事件,我通过执行以下操作创建:

EventWaitHandle notifyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, notifyEventName, out createdEvent);
Run Code Online (Sandbox Code Playgroud)

几个进程创建此事件(例如,它们在它们之间共享).它用于通知何时更新内容.

我希望能够设置此事件,以便在其上发出等待的所有进程,然后立即重置它,以便阻止事件的后续Waits.

如果我做了

notifyEvent.Set();
notifyEvent.Reset();
Run Code Online (Sandbox Code Playgroud)

它有时会通知所有监听过程.

如果我做了

notifyEvent.Set();
Thread.Sleep(0);
notifyEvent.Reset();
Run Code Online (Sandbox Code Playgroud)

更多进程得到通知(我认为这会发生,因为调度程序有机会运行).

如果我这样做

notifyEvent.Set();
Thread.Sleep(100);
notifyEvent.Reset();
Run Code Online (Sandbox Code Playgroud)

然后一切似乎都很好,所有过程(例如~8)都会得到一致的通知.我不喜欢在睡眠呼叫中使用"幻数".

是否有更好的方法通知所有侦听器在其他进程中发生事件已发生的事件,以便在通知时收听事件信号的每个人都会立即重置事件,以便其他任何人去听该事件会阻止吗?

更新:信号量似乎不适合这里,因为事件的听众数量会随着时间的推移而变化.事先并不知道甚至需要通知时会有多少听众.

Spe*_*ort 2

您错误地使用了 EventWaitHandle 类。重置事件不应用于向多个线程发出信号。相反,您需要为每个线程创建一个重置事件,然后当您准备好时循环遍历所有线程并使用 Set()。主线程不应调用 Reset() 方法。可以这么说,每个线程都应该负责关闭它们后面的门。

这是一个基本示例:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)