1

我正在编写一个类 ( PipeReader) 来处理 Windows 上的命名管道。该类使用异步 IO 从管道中读取。

到目前为止,我一直在没有事件循环的线程中使用该类,我不得不等待 IO 完成使用SleepEx()并且它有效。

现在我有一个带有事件循环的第二个线程和PipeReader该类的第二个实例,但是永远不会调用第二个实例的完成例程。

致电CreateFile()

handle = CreateFile(fullServerName,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         NULL,
                         OPEN_EXISTING,
                         FILE_FLAG_OVERLAPPED,
                         NULL);

致电ReadFileEx()

BOOL status = ReadFileEx(m_handle, ptr, readSize, &m_overlapped, &PipeReader::readFileCompleted);

在线程 1 中等待的代码,有效:

while (SleepEx(msecs < 0 ? INFINITE : msecs, TRUE) == WAIT_IO_COMPLETION) {
    if (m_readFinished) // Set to true in the completion routine
        return true;

    msecs = // decrease msecs by the amount elapsed
    if (!msecs)
        break;
}

线程 2 中从不调用完成例程的事件循环代码:

forever()
{
    forever()
    {
        bool haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);

        if (haveMessage)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            break; //No message leave loop
        }
    }


    HANDLE handles[1];
    handles[0] = m_hwnd;
    DWORD result = MsgWaitForMultipleObjectsEx(1, handles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE|MWMO_INPUTAVAILABLE);

}

编辑:

如果我将调用替换为MsgWaitForMultipleObjectsEx()

WaitForSingleObjectEx(m_hwnd, INFINITE, TRUE);

它仍然不起作用。但是,如果我SleepEx()在事件循环中使用它就可以了。

4

1 回答 1

3

这是因为m_hwnd不是内核句柄。因此WaitForSingleObjectEx失败WAIT_FAILEDGetLastError返回ERROR_INVALID_HANDLE- 结果线程永远不会进入警报等待并且永远不会执行 APC。您需要有另一个消息循环,例如:

  for ( ; ; ) {

    MSG msg;

    switch(MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE| MWMO_ALERTABLE)) 
    {

    case STATUS_WAIT_0 : 

      while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {

        switch(msg.message) {
        case WM_QUIT: 
          return;
        default: 
          if (!IsDialogMessage(hwnd, &msg))
          {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
      }
    }
    case WAIT_IO_COMPLETION :
    // apc called
    continue;
    default: return ;
    }
于 2017-07-26T15:28:08.337 回答