Hi all,
I'm trying to use the Win32 API to make a sub-thread that reads from STD_INPUT_HANDLE and pushes the bytes it reads into a socket. Because I want to be able to shut down this thread safely when it's time to exit, I'm using ReadFileEx() and overlapped I/O instead of plain old blocking ReadFile(). The idea is that my thread will wait in WaitForSingleObject() instead of in ReadFile(), and when the main thread wants the slave thread to go away, it will signal on that object, the slave thread will wake up and exit, and then the main thread can continue its shutdown sequence.
My problem is this: despite the documentation saying that ReadFileEx() is asynchronous and thus won't ever block... my slave thread is still blocking inside ReadFileEx(). (I inserted printf's in the event loop to verify where it was blocking) Because of this, my main thread can't shut the slave thread down, and thus main program never exits.
Am I doing something wrong, or is ReadFileEx() meant to block when reading from stdin? If the latter, what is the solution to the thread shutdown problem? The slave thread's entry function is below for your persual...
[... in the main thread, before the slave thread is spawned...]
_stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
_wakeupSignal = CreateEvent(0, false, false, 0);
[...]
VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap)
{
printf("CompletedReadRoutine dwErr=%li cbBytesRead=%li overlap=%p\n", dwErr, cbBytesRead, lpOverLap);
}
void StdinDataIO :: IOThreadEntry()
{
char buf[4096];
OVERLAPPED olap;
bool keepGoing = true;
bool overlappedReadPending = false;
while(keepGoing)
{
if (overlappedReadPending)
{
DWORD waitResult = WaitForSingleObjectEx(_wakeupSignal, INFINITE, true);
switch(waitResult)
{
case WAIT_IO_COMPLETION:
{
overlappedReadPending = false;
DWORD numBytesRead;
if ((GetOverlappedResult(_stdinHandle, &olap, &numBytesRead, true) == false)||(SendData(_slaveSocket, buf, numBytesRead, true) != numBytesRead)) keepGoing = false;
}
break;
default:
keepGoing = false;
break;
}
}
else
{
memset(&olap, 0, sizeof(olap));
if (ReadFileEx(_stdinHandle, buf, sizeof(buf), &olap, CompletedReadRoutine)) overlappedReadPending = true;
else keepGoing = false;
}
}
if (overlappedReadPending) CancelIo(_stdinHandle);
_slaveSocket.Reset(); // this alerts the main thread that we are gone
}