【问题标题】:ReadFileEx() completion routine not called未调用 ReadFileEx() 完成例程
【发布时间】:2018-01-01 22:40:24
【问题描述】:

我正在编写一个类 (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(),它就可以工作。

【问题讨论】:

    标签: c++ windows winapi asynchronous overlapped-io


    【解决方案1】:

    这是因为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 ;
        }
    

    【讨论】:

    • 谢谢它的工作。我有一个错误的想法,我必须等待 HWND 能够使用 PostMessage() 唤醒它。
    • @BenjaminT 不,您不需要等待 hwnd(也不能)。并且您需要首先调用 MsgWaitForMultipleObjectsEx 并且仅当它返回 STATUS_WAIT_0 + n (其中 n 个句柄) - 在循环中调用 PeekMessage 而它返回 true
    猜你喜欢
    • 2015-08-04
    • 1970-01-01
    • 2021-03-18
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    相关资源
    最近更新 更多