代码之家  ›  专栏  ›  技术社区  ›  Frerich Raabe

如何正确读取子进程的stdout/stderr输出?

  •  2
  • Frerich Raabe  · 技术社区  · 16 年前

    我写了一个程序 a.exe b.exe ,使用 CreateProcess 功能。调用者创建两个管道,并将两个管道的写入端作为stdout/stderr句柄传递给CreateProcess,以用于子进程。这实际上与 Creating a Child Process with Redirected Input and Output MSDN上的样本确实如此。

    在stdout或stderr上的数据可用 WaitForMultipleObjects 函数在管道上不起作用),调用程序有两个运行的线程,这两个线程都执行(阻塞) ReadFile 调用stdout/stderr管道的读取端;下面是用于stdout/stderr的“read thread procedure”的确切代码(我并不是自己写这段代码的,我想是一些同事写的):

    DWORD __stdcall ReadDataProc( void *handle )
    {
        char buf[ 1024 ];
        DWORD nread;
        while ( ReadFile( (HANDLE)handle, buf, sizeof( buf ), &nread, NULL ) &&
                GetLastError() != ERROR_BROKEN_PIPE ) {
            if ( nread > 0 ) {
                fwrite( buf, nread, 1, stdout );
            }
        }
        fflush( stdout );
        return 0;
    }
    

    然后使用一个简单的 WaitForSingleObject b、 执行 终止。一旦该调用返回,两个读取线程就会终止(因为管道断开),并且两个管道的读取端都将使用 CloseHandle .

    现在,我遇到的问题是: 可以 (取决于用户输入)启动比 b、 执行 守护进程本身基本上就是进程。在这种情况下,stdout/stderr管道的写入端被继承到该守护进程,因此管道永远不会中断。这意味着WaitForSingleObject调用 返回(因为 b、 执行 完成),但是对任何一个管道的CloseHandle调用都会阻塞,因为两个读取线程仍然位于各自的位置(阻塞!)ReadFile调用。

    我如何解决这个问题而不终止两个读线程与暴力( TerminateThread )之后 b、 执行 返回?如果可能的话,我希望避免任何涉及管道和/或进程轮询的解决方案。

    更新: 以下是我迄今为止尝试的:

    1. 没有 b、 执行 继承 a、 执行
    2. :似乎没有任何效果(如果有,我会感到惊讶)。
    3. ReadDataProc 程序(在两个管道上读取)考虑 b、 执行 除了检查 ERROR_BROKEN_PIPE
    4 回复  |  直到 12 年前
        1
  •  2
  •   adf88    16 年前
    1. 使用命名管道和异步ReadFile

    2. 分析从管道读取的输出,寻找结束(在您的情况下可能太复杂)。
        2
  •  1
  •   Roman Cheplyaka    16 年前

    在这种情况下发生的是 管道继承到该守护进程

    应该

        3
  •  0
  •   Community Mohan Dere    9 年前

    在Windows Vista之前的Windows版本上(您可以使用 CancelSynchronousIO 函数,则无法使用终止读取线程 TerminateThread .

    合适的替代品( suggested by adf88 )可能是使用异步 ReadFile 调用,但这在我的情况下是不可能的(需要对现有代码进行太多更改)。

        4
  •  0
  •   Alexandr Poltavsky    12 年前

    设置一些全局标志(bool exit \u标志)并在a.exe中向管道写入一些内容