在Windows上等待进程或标准输出

Waiting for a process or stdout on Windows

本文关键字:标准输出 进程 等待 Windows      更新时间:2023-10-16

我正在使用 CreateProcess 启动一个进程,我想等待该进程完成,或者等待任何内容写入标准输出,该进程正在通过匿名管道管道传输。下面的代码不起作用,因为 WaitForMultipleObjects 不断返回 stdout 管道,即使没有什么可读的。有没有办法等待管道?我迫不及待地想阅读,因为如果该过程完成,我还需要继续。我也不能等到该过程完成而不检查管道,因为它可能会溢出。有什么想法吗?

if (::CreateProcess(
    (!application_name.empty() ? application_name.c_str() : NULL),  // Application/Executable name, if supplied.
    lpCommandLine,                                                  // Arguments or Executable and Arguments
    NULL,                               // Process Attributes
    NULL,                               // Thread Attributes
    TRUE,                               // Inherit handles
    CREATE_NO_WINDOW,                   // Create flags
    NULL,                               // Environment (Inherit)
    current_directory.c_str(),          // Working Directory
    &m_startup_info,                    // Startup Info
    &process_info                       // Process Info
))
{
    HANDLE  handles[2];
    bool    waiting = true;
    handles[0] = process_info.hProcess;
    handles[1] = m_read_stdout; // previously created with CreatePipe. One end handed to CreateProcess
    // Must process stdout otherwise the process may block if it's output buffer fills!!
    while (waiting)
    {
        DWORD r = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
        switch (r)
        {
        case WAIT_OBJECT_0+0:
            waiting = false;
            break;
        case WAIT_OBJECT_0+1:
            AppendSTDOUTFromProcess(output);
            break;
        default:
            ATLASSERT(FALSE);
            break;
        }
    }
}

管道不是可等待的对象,因此不能在WaitFor...()函数中使用它们。 您可以:

  1. 使用 WaitForSingleObject() 仅等待进程句柄,并为其提供超时,以便循环定期唤醒,然后它可以调用 PeekNamedPipe() 来检查管道中的数据。

  2. 在单独的线程中执行管道读取,在没有数据可用时让读取块,然后在管道关闭时终止线程。然后,您可以使用WaitForMultipleObjects()等待进程和线程句柄。

  3. 根本不要等待进程句柄。只需让循环从管道读取,在没有可用数据时阻塞,直到管道关闭时读取失败。这是Microsoft的示例使用的方法。