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

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

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

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

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

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

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

Спасибо за помощь

Edit:

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

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

создать поток:

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("GlobalConsumerCloseEvent"));

        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("GlobalConsumerCloseEvent")  // 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 не замечает измененный сигнал и не закрывается.

Edit 2:

после использования GetLastError (); я смог определить, что дескриптор OpenEvent был нулевым, ошибка задана

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

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

2 ответов


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

Процесс 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);
}

Б

// 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);
}

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

// 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);
  }
}

звучит так, как будто вы можете использовать CreateSemaphore. Семафор можно использовать для представления количества элементов данных, доступных для обработки процессом B. Инициализируйте его до 0, когда элемент данных становится доступным, увеличьте его с помощью ReleaseSemaphore. Затем в процессе вызова WaitForSingleObject, или один из его bretheren, который вернется только тогда, когда количество семафоров выше 0, в этот момент количество уменьшается.

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