Win32:STD_IN_HANDLE块上的ReadFileEx(),为什么?

时间:2009-08-22 04:43:11

标签: multithreading winapi stdin

我正在尝试使用Win32 API创建一个从STD_INPUT_HANDLE读取的子线程,并将其读取的字节推送到套接字。因为我希望能够在退出时安全地关闭这个线程,所以我使用的是ReadFileEx()和重叠的I / O而不是普通的旧的阻塞ReadFile()。我的想法是我的线程将在WaitForSingleObject()而不是在ReadFile()中等待,并且当主线程希望从属线程消失时,它将在该对象上发出信号,从属线程将唤醒并退出,然后主线程可以继续关闭序列。

我的问题是:尽管文档说ReadFileEx()是异步的,因此不会阻塞...我的从属线程仍然在ReadFileEx()内阻塞。 (我在事件循环中插入printf来验证它阻塞的位置)因此,我的主线程无法关闭从属线程,因此主程序永远不会退出。

我做错了什么,或者是从stdin读取时是否意味着阻止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 个答案:

答案 0 :(得分:4)

ReadFileEx的文档中描述了您可以传递的文件句柄类型:

  

此文件句柄必须已经存在   使用FILE_FLAG_OVERLAPPED创建   标志,必须有GENERIC_READ   访问权。

否则,ReadFileEx会在您使用未使用FILE_FLAG_OVERLAPPED打开的句柄调用时阻止。

您也可以在WaitForSingleObject返回的句柄上调用GetStdHandle或其他同步函数,并调用_kbhit或其他一些控制台事件处理组合,如果您想确保输入可用。