I have an application consisting of two windows, one communicates to the other and sends it a struct constaining two integers (In this case two rolls of a dice).
I will be using events for the following circumstances:
I have noticed that if the second process is constantly waiting for the first process to send data then the program will be just sat waiting, which is where the idea of implementing threads on each process occurred and I have started to implement this already.
The problem i'm having is that I don't exactly have a lot of experience with threads and events so I'm not sure of the best way to actually implement what I want to do.
I'm trying to work out how the other process will know of the event being fired so it can do the tasks it needs to do, I don't understand how one process that is separate from another can tell what the states the events are in especially as it needs to act as soon as the event has changed state.
Thanks for any help
Edit:
I can only use the Create/Set/Open methods for events, sorry for not mentioning it earlier.
Furthermore, I create a new thread in process A which lets the user interact with the application whilst listening for the close event.
Create thread:
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);
}
Opening event on A when B closes:
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;
}
}
}
Creating event in b (In 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);
}
Setting the event to signalled when B closes:
case WM_DESTROY:
{
SetEvent(hConsumerCloseEvent);
PostQuitMessage(0);
break;
}
As you can see when the Event is signalled, application A is set to close. When I run both application and close process B, process A does not notice the changed signal and does not close.
Edit 2:
After using the GetLastError(); I was able to identify that the handle to the OpenEvent was NULL, the error given is
ERROR_FILE_NOT_FOUND - 2 :The system cannot find the file specified
Is my method of creating the event and reading it incorrect, I've made sure to include the Global\ prefix.
If the process is privileged, send the signal to all processes except for some special system processes. Otherwise, send the signal to all processes with the same effective user ID. A process can send a signal to itself with a call like kill (getpid(), signum ) .
Sending a Signal to Another Process: System Call kill() System call kill() takes two arguments. The first, pid, is the process ID you want to send a signal to, and the second, sig, is the signal you want to send. Therefore, you have to find some way to know the process ID of the other party.
The EventSignal function defines and communicates the occurrence of events. The signal is always associated with the process under which EventSignal is executed. An event may be defined so that its signal is recognizable only within the process in which it occurred or throughout the session containing that process.
The nice thing about semaphores is that they single handedly take care of synchronizing the queue depth between the two processes. Since you're limited to using Event objects instead I'd suggest having the inter-process messages instead of a queue, or a queue of one if you will.
Process 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);
}
Process 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);
}
If, as I'm guessing, you actually want to have a queue of length more than one you can now implement the queueing logic in process b. You'll want to do that in a separate thread for a couple of reasons. Implementation of the queue logic is up to you. Depending on your efficiency needs it could be a circular array or linked list or ???.
// 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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With