Как отправить сигнал о событии через процессы - C - PullRequest
6 голосов
/ 22 апреля 2010

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

Я буду использовать события для следующих обстоятельств:

  • Процесс a отправляет данные процессу b, процесс b отображает данные
  • Процесс a закрывается, в свою очередь процесс закрытия b
  • Процесс b закрывает a, в свою очередь закрывает процесс a

Я заметил, что если второй процесс постоянно ожидает, пока первый процесс отправит данные, тогда программа просто будет сидеть в ожидании, и именно здесь возникла идея реализации потоков для каждого процесса, и я уже начал реализовывать это уже .

Проблема, с которой я столкнулся, заключается в том, что у меня нет особого опыта работы с потоками и событиями, поэтому я не уверен, что лучше всего реализовать то, что я хочу сделать.

Я пытаюсь понять, как другой процесс узнает о событии, которое запускается, чтобы он мог выполнять задачи, которые ему нужны, я не понимаю, как один процесс, отдельный от другого, может сказать, в каких состояниях события, в частности, должны действовать, как только событие изменило состояние.

Спасибо за любую помощь

Edit:

Я могу использовать только методы Create / Set / Open для событий, извините, что не упомянул об этом раньше.

Кроме того , я создаю новый поток в процессе A, который позволяет пользователю взаимодействовать с приложением во время прослушивания события close.

Создать тему:

hCreateEventThread = CreateThread(
                NULL,       // lpThreadAttributes (default)
                0,          // dwStackSize (default)
                ThreadFunc, // lpStartAddress
                NULL,       // lpParameter
                0,          // dwCreationFlags
                &hCreateEventThreadID   // lpThreadId (returned by function)
                );

            if(hCreateEventThread != NULL)
            {
                MessageBox(hMainWindow,L"Thread created!",L"Success!",MB_OK);
            }

Открытие события A при закрытии B :

    DWORD WINAPI ThreadFunc(LPVOID passedHandle)
    {
        hConsumerCloseEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("Global\\ConsumerCloseEvent"));

        while(TRUE)
        {
            dwCloseResult = WaitForSingleObject(hConsumerCloseEvent,INFINITE);

            switch (dwCloseResult) 
            {
                // State of object is signalled
            case WAIT_OBJECT_0: 
                //Consumer has closed, exit program.
                //CloseHandle(hDiceRoll);
                //CloseHandle(hCloseEvent);
                //CloseHandle(hCreateEventThread);
                ExitProcess(1);
                break;
            default: 
                return;
            }
        }
    }

Создание события в b (в WM_CREATE):

hConsumerCloseEvent = CreateEvent( 
                NULL,               // default security attributes
                TRUE,               // manual-reset event
                TRUE,              // initial state is nonsignaled
                TEXT("Global\\ConsumerCloseEvent")  // object name
                );

            if(hConsumerCloseEvent == NULL)
            {
                MessageBox(hMainWindow,L"CreateEvent failed",L"Error",MB_OK);
            }

Установка события, сигнализируемого при закрытии B:

case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }

Как видно из сообщения о событии, приложение A закрывается. Когда я запускаю приложение и закрываю процесс B, процесс A не замечает измененный сигнал и не закрывается.

Редактировать 2:

После использования GetLastError (); Мне удалось идентифицировать, что дескриптор OpenEvent был НЕДЕЙСТВИТЕЛЕН, выданная ошибка

ERROR_FILE_NOT_FOUND - 2: система не могу найти указанный файл

Является ли мой метод создания события и его чтения некорректным, я обязательно включил префикс Global \.

Ответы [ 2 ]

3 голосов
/ 25 апреля 2010

Приятной особенностью семафоров является то, что они в одиночку заботятся о синхронизации глубины очереди между двумя процессами.Поскольку вы ограничены использованием объектов Event вместо этого, я бы предложил использовать межпроцессные сообщения вместо очереди или одну очередь, если хотите.

Процесс A

// In the initialization code
...
hMessageEmptiedEvent = CreateEvent(NULL, FALSE, TRUE, _T("MessageEmptied"));
hMessageSentEvent = CreateEvent(NULL, FALSE, FALSE, _T("MessageSent"));

// Call this function when you want to send the data to process b
void sendData(struct diceData data)
{
  // Make sure any pre-existing message has been processed
  WaitForSingleObject(hMessageEmptiedEvent, INFINITE);
  // Copy the data into the shared buffer
  *(struct diceData *) pBuf = data;
  // Signal the other process that data is ready
  SetEvent(hMessageSentEvnt);
}

Процесс B

// In the initialization code
...
hMessageEmptiedEvent = CreateEvent(NULL, FALSE, TRUE, _T("MessageEmptied"));
hMessageSentEvent = CreateEvent(NULL, FALSE, FALSE, _T("MessageSent"));

// Call this function when you want to recieve data from process a
struct diceData readData()
{
  struct diceData data;

  // Wait for a message to become available
  WaitForSingleObject(hMessageSentEvent, INFINITE);
  // Copy the data from the shared buffer
  data = * (struct diceData *)pBuf;
  // Signal the other process that message has been read.
  SetEvent(hMessageEmptiedEvnt);
}

Если, как я догадываюсь, вы на самом деле хотите иметь очередь длиной больше, чем выТеперь реализуйте логику очередей в процессе б.Вы захотите сделать это в отдельной ветке по нескольким причинам.Реализация логики очереди зависит от вас.В зависимости от ваших потребностей эффективности это может быть круговой массив или связанный список или ???.

// In process b's initialzation add a thread to do the queueing
initializeEmptyQueue();
hQueueingThread = CreateThread(NULL, 0, enqueueLoop, NULL, 0, NULL);


DWORD enqueueLoop(LPVOID ignored)
{
  while (TRUE)
  {
    struct diceData data;
    data = getData();
    enqueueData(data);
  }
}
2 голосов
/ 22 апреля 2010

Звучит так, как вы, возможно, захотите использовать <a href="http://msdn.microsoft.com/en-us/library/ms682438(VS.85).aspx" rel="nofollow noreferrer">CreateSemaphore</a>. Вы можете использовать семафор для представления количества элементов данных, доступных для процесса b для обработки. Инициализируйте его счетом 0, когда элемент данных становится доступным, увеличивая его на <a href="http://msdn.microsoft.com/en-us/library/ms685071(VS.85).aspx" rel="nofollow noreferrer">ReleaseSemaphore</a>. Затем в вашем процессе b вызовите <a href="http://msdn.microsoft.com/en-us/library/ms687032(VS.85).aspx" rel="nofollow noreferrer">WaitForSingleObject</a> или одного из его братьев, который вернется только тогда, когда счетчик семафоров превысит 0, и в этот момент счетчик уменьшится.

Это не полное решение, потому что вам все еще нужно обрабатывать такие вещи, как то, что нужно делать, когда ваш общий буфер заполнен, но это должно помочь вам хорошо и по-настоящему начать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...