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:
- Process a sends data to process b, process b displays data
- Process a closes, in turn closing process b
- Process b closes a, in turn closing process a
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.
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);
}
}
Sounds like you might want to use CreateSemaphore
. You can use a semaphore to represent the number of data items available for process b to handle. Initialise it to a count of 0, when a data item is made available increment it with ReleaseSemaphore
. Then in your process b call WaitForSingleObject
, or one of its bretheren, which will only return when the semaphore count is above 0, at which point the count is decremented.
This isn't complete solution because you still need to handle things like what to do when your shared buffer is full, but is should get you well and truly started.
精彩评论