Win32: ReadFileEx () для блоков STD_IN_HANDLE, почему? - PullRequest
4 голосов
/ 22 августа 2009

Я пытаюсь использовать 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
}

1 Ответ

4 голосов
/ 22 августа 2009

Из документации ReadFileEx, описывающей тип файлового дескриптора, который вы можете передать:

Этот дескриптор файла должен быть создан с помощью FILE_FLAG_OVERLAPPED флаг и должен иметь GENERIC_READ право доступа.

В противном случае ReadFileEx будет блокироваться, когда вы вызываете его с помощью дескриптора, который не открывается с помощью FILE_FLAG_OVERLAPPED.

Вы также можете вызвать WaitForSingleObject или другую функцию синхронизации для дескриптора, возвращенного GetStdHandle, и вызвать _kbhit или другую комбинацию обработки событий консоли, если вы хотите убедиться, что ввод доступен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...