Как отправить сигнал события через процессы - 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, в этот момент количество уменьшается.
Это не полное решение, потому что вам все еще нужно обрабатывать вещи например, что делать, когда ваш общий буфер заполнен, но это должно помочь вам хорошо и по-настоящему начать.