【问题标题】:Win32: ReadFileEx() on STD_IN_HANDLE blocks, why?Win32:STD_IN_HANDLE 块上的 ReadFileEx(),为什么?
【发布时间】:2009-08-22 04:43:10
【问题描述】:

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

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

我做错了什么,还是 ReadFileEx() 在从标准输入读取时被阻止?如果是后者,线程关闭问题的解决方案是什么?下面是slave线程的入口函数,供大家参考……

[... 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
}

【问题讨论】:

    标签: multithreading winapi stdin


    【解决方案1】:

    来自ReadFileEx的文档描述了你可以传入什么样的文件句柄:

    这个文件句柄必须是 使用 FILE_FLAG_OVERLAPPED 创建 标志并且必须具有 GENERIC_READ 访问权限。

    否则,ReadFileEx 将在您使用未使用FILE_FLAG_OVERLAPPED 打开的句柄调用它时阻塞。

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

    【讨论】:

    • 我担心是这样的。我不认为 CONIN$ 技巧会做我想做的事,因为我不仅需要能够从键盘读取,还需要能够从父进程或文件重定向中读取......
    猜你喜欢
    • 1970-01-01
    • 2014-03-31
    • 2015-12-05
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    相关资源
    最近更新 更多