开发者

Wait until all processes notified after EventWaitHandle.Set()

I do in one process:

_eventWaitHandle.Set();
_eventWaitHandle.Reset();

In another process:

_eventWaitHandle.WaitOne();
Console.WriteLine("Hello");

But never get notified (no console output). It seem that Set in asynchronous.

How can I wait until all waiters were signaled before doing Reset()?

I create wait handle (NAMED inter process wait handle):

    internal static EventWaitHandle OpenExistingOrCreateEventWaitHandle(string name)
    {
        try
        {
            return EventWaitHandle.OpenExisting(name);
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            return new EventWaitHandle(false, EventResetMode.ManualReset, name);
        }
    }

UPDATE

For now I have one "solution"

_eventWaitHandle.Set();
Thread.Sleep(10);
_eventWaitHandle.Reset();

Second possible - to have many handles for each process. But this code should work in any office application add-in or standalone app.开发者_Go百科 So names should be generated some how and discovered.

Third - to use WCF p2p(netPeerTcpBinding) or named pipes with UdpDiscoveryEndpoint- but these use "IP" so can have some security issues when deployed to end users?


Yes the Set() function exits imemdiately, so having Set() and Reset() called as you do basically does nothing, or does something randomly. You can solve the issue by resetting the event on the listening thread, after the WaitOne().


You can set the EventResetMode to EventResetMode.AutoReset, doing so, it will automatically reset the event when one of the process take the event. You wont have to reset it manually after.

Having multiple process, you could create an event for each listener and trigger them all when you have to signal the event.

foreach(var process in _myProcesses)
{
    waitHandles.Add(OpenExistingOrCreateEventWaitHandle(process.SharedWaitHandleName);
}

...

internal static EventWaitHandle OpenExistingOrCreateEventWaitHandle(string name)
{
    try
    {
        return EventWaitHandle.OpenExisting(name);
    }
    catch (WaitHandleCannotBeOpenedException)
    {
        return new EventWaitHandle(false, EventResetMode.AutoReset, name);
    }
}


...


foreach(var waitHandle in waitHandles)
{
    waitHandle.Set();
}


If you want to know how to wait until all waiters were signaled before doing Reset() where the waiters are different threads in the same process, then take a look at this example from the MSDN page of the EventWaitHandle class

using System;
using System.Threading;

public class Example
{
    // The EventWaitHandle used to demonstrate the difference
    // between AutoReset and ManualReset synchronization events.
    //
    private static EventWaitHandle ewh;

    // A counter to make sure all threads are started and
    // blocked before any are released. A Long is used to show
    // the use of the 64-bit Interlocked methods.
    //
    private static long threadCount = 0;

    // An AutoReset event that allows the main thread to block
    // until an exiting thread has decremented the count.
    //
    private static EventWaitHandle clearCount = 
        new EventWaitHandle(false, EventResetMode.AutoReset);

    [MTAThread]
    public static void Main()
    {
        // Create an AutoReset EventWaitHandle.
        //
        ewh = new EventWaitHandle(false, EventResetMode.AutoReset);

        // Create and start five numbered threads. Use the
        // ParameterizedThreadStart delegate, so the thread
        // number can be passed as an argument to the Start 
        // method.
        for (int i = 0; i <= 4; i++)
        {
            Thread t = new Thread(
                new ParameterizedThreadStart(ThreadProc)
            );
            t.Start(i);
        }

        // Wait until all the threads have started and blocked.
        // When multiple threads use a 64-bit value on a 32-bit
        // system, you must access the value through the
        // Interlocked class to guarantee thread safety.
        //
        while (Interlocked.Read(ref threadCount) < 5)
        {
            Thread.Sleep(500);
        }

        // Release one thread each time the user presses ENTER,
        // until all threads have been released.
        //
        while (Interlocked.Read(ref threadCount) > 0)
        {
            Console.WriteLine("Press ENTER to release a waiting thread.");
            Console.ReadLine();

            // SignalAndWait signals the EventWaitHandle, which
            // releases exactly one thread before resetting, 
            // because it was created with AutoReset mode. 
            // SignalAndWait then blocks on clearCount, to 
            // allow the signaled thread to decrement the count
            // before looping again.
            //
            WaitHandle.SignalAndWait(ewh, clearCount);
        }
        Console.WriteLine();

        // Create a ManualReset EventWaitHandle.
        //
        ewh = new EventWaitHandle(false, EventResetMode.ManualReset);

        // Create and start five more numbered threads.
        //
        for(int i=0; i<=4; i++)
        {
            Thread t = new Thread(
                new ParameterizedThreadStart(ThreadProc)
            );
            t.Start(i);
        }

        // Wait until all the threads have started and blocked.
        //
        while (Interlocked.Read(ref threadCount) < 5)
        {
            Thread.Sleep(500);
        }

        // Because the EventWaitHandle was created with
        // ManualReset mode, signaling it releases all the
        // waiting threads.
        //
        Console.WriteLine("Press ENTER to release the waiting threads.");
        Console.ReadLine();
        ewh.Set();

    }

    public static void ThreadProc(object data)
    {
        int index = (int) data;

        Console.WriteLine("Thread {0} blocks.", data);
        // Increment the count of blocked threads.
        Interlocked.Increment(ref threadCount);

        // Wait on the EventWaitHandle.
        ewh.WaitOne();

        Console.WriteLine("Thread {0} exits.", data);
        // Decrement the count of blocked threads.
        Interlocked.Decrement(ref threadCount);

        // After signaling ewh, the main thread blocks on
        // clearCount until the signaled thread has 
        // decremented the count. Signal it now.
        //
        clearCount.Set();
    }
}


I solved problem. I used memory mapped file to store list of event wait handles names. Timeout failed to work stably. Current solution works in production during 2 years.

To have p2p like IPC desktop events I used next receipt:

  • 1 shared mutex
  • 1 unique waiter and 1 unique responder event wait handle per process (eventing participant)
  • 1 memory mapped file to store registry of participants waiting (could use real registry for this)
  • 1 memory mapped file for event data exchanged


Use EventResetMode.Manual and store your EventWaitHandle in a static. Consumers should read the handle from this static. Whenever you are about to call Set(), first create a new EventWaitHandle and store it in that static. The next time a consumer wants a handle he will get the new one, which is clear.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜