Я пытаюсь использовать Win32 API для создания подпотока, который читает из STD_INPUT_HANDLE и помещает байты, которые он читает, в сокет. Поскольку я хочу иметь возможность безопасно завершать этот поток при выходе из него, я использую ReadFileEx () и перекрывающийся ввод-вывод вместо простого старого блокирующего ReadFile (). Идея состоит в том, что мой поток будет ждать в WaitForSingleObject () вместо ReadFile (), и когда основной поток хочет, чтобы подчиненный поток ушел, он подаст сигнал на этот объект, подчиненный поток проснется и выйдет, а затем главный поток может продолжить свою последовательность выключения.
Моя проблема заключается в следующем: несмотря на документацию, в которой говорится, что ReadFileEx () является асинхронным и, следовательно, никогда не блокируется ... мой подчиненный поток по-прежнему блокируется внутри ReadFileEx (). (Я вставил printf в цикл обработки событий, чтобы проверить, где он блокировался). Из-за этого мой основной поток не может закрыть подчиненный поток, и поэтому основная программа никогда не завершается.
Я делаю что-то не так, или ReadFileEx () предназначен для блокировки при чтении из стандартного ввода? Если последнее, каково решение проблемы отключения потока? Функция ввода подчиненного потока ниже для вашего личного ...
[... 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
}