等待Windows上的进程或stdout

时间:2016-02-19 06:41:20

标签: c++ windows

我正在使用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;
        }
    }
}

1 个答案:

答案 0 :(得分:3)

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

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

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

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