Подождите, пока все процессы не будут уведомлены после EventWaitHandle.Set () - PullRequest
1 голос
/ 31 августа 2011

я делаю за один процесс :

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

В другом процессе :

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

Но никогда не получать уведомления (без вывода на консоль). Кажется, что Set в асинхронном режиме.

Как я могу подождать, пока все официанты не получат сигнал перед выполнением сброса ()?

Я создаю дескриптор ожидания ( NAMED дескриптор ожидания между процессами ):

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

UPDATE

Пока у меня есть одно "решение"

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

Второй вариант - иметь много дескрипторов для каждого процесса. Но этот код должен работать в любой надстройке офисного приложения или автономном приложении. Поэтому имена должны быть сгенерированы как и как.

Третье - использовать WCF p2p (netPeerTcpBinding) или именованные каналы с UdpDiscoveryEndpoint, но они используют «IP», поэтому могут возникнуть проблемы с безопасностью при развертывании для конечных пользователей?

Ответы [ 5 ]

2 голосов
/ 31 августа 2011

Да, функция Set() немедленно завершается, поэтому вызовы Set() и Reset(), как вы делаете, в основном ничего не делают или делают что-то случайное.Вы можете решить эту проблему, сбросив событие в потоке прослушивания после WaitOne().

1 голос
/ 31 августа 2011

Вы можете установить EventResetMode на EventResetMode.AutoReset, при этом оно автоматически сбросит событие, когда один из процессов получит событие. Вам не нужно будет сбрасывать его вручную после.

Имея несколько процессов, вы можете создать событие для каждого слушателя и запускать их все, когда вам нужно сообщить о событии.

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();
}
0 голосов
/ 09 июня 2017

Используйте EventResetMode.Manual и сохраняйте EventWaitHandle в статическом виде.Потребители должны прочитать ручку из этой статики.Всякий раз, когда вы собираетесь вызвать Set (), сначала создайте новый EventWaitHandle и сохраните его в этом static.В следующий раз, когда потребитель захочет получить ручку, он получит новую, что понятно.

0 голосов
/ 06 августа 2013

Я решил проблему. Я использовал файл отображения памяти для хранения списка имен дескрипторов ожидающих событий. Тайм-аут не работал стабильно. Текущее решение работает в производстве в течение 2 лет.

Чтобы иметь p2p-подобные события на рабочем столе IPC, я использовал следующую квитанцию:

  • 1 общий мьютекс
  • 1 уникальный официант и 1 уникальный обработчик ожидания события респондента на процесс (участник события)
  • 1 отображенный в памяти файл для хранения реестра ожидающих участников (может использовать для этого реальный реестр)
  • 1 отображенный в памяти файл для обмена данными о событиях
0 голосов
/ 31 августа 2011

Если вы хотите знать, как ждать, пока все официанты не будут оповещены, прежде чем выполнять Reset (), где официанты - это разные потоки в одном и том же процессе, посмотрите на этот пример со страницы MSDN EventWaitHandle класс

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();
    }
}
...