簡體   English   中英

ERROR_BROKEN_PIPE無法讀取進程終止之前產生的進程輸出

[英]ERROR_BROKEN_PIPE cannot read process output produced before process termination

我在Win32中有一個簡單的過程重定向例程。 這里的問題是,如果我在子進程stdout的讀取之間放置一個Sleep,則當我在睡眠時終止該進程時,我只會錯過輸出ERROR_BROKEN_PIPE的管道中的最后一個字節。 看來,一旦子進程終止,它的管道和關聯的句柄就會關閉,所有待處理的東西都會被丟棄。 唯一的解決方案似乎是盡可能快地從管道中讀取File,但是由於軟件的設計,這對我來說不只是一個問題。

int _tmain(int argc, _TCHAR* argv[])
{
    BOOL bSuccess;
    WCHAR szCmdLine[MAX_PATH];
    char chBuf[BUFSIZE];
    DWORD dwRead;
    HANDLE g_hChildStd_OUT_Rd2 = NULL;
    HANDLE g_hChildStd_OUT_Wr2 = NULL;
    SECURITY_ATTRIBUTES saAttr2; 
    STARTUPINFO si2;
    PROCESS_INFORMATION pi2;

    ZeroMemory( &si2, sizeof(si2) );
    si2.cb = sizeof(si2);
    ZeroMemory( &pi2, sizeof(pi2) );
    //create pipe
    saAttr2.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr2.bInheritHandle = TRUE; 
    saAttr2.lpSecurityDescriptor = NULL; 
    assert(CreatePipe(&g_hChildStd_OUT_Rd2, &g_hChildStd_OUT_Wr2, &saAttr2, 0));
    //create child process
    bSuccess = FALSE;
    memset(szCmdLine, 0, MAX_PATH);
    wsprintf(szCmdLine, L"c:\\myprocess.exe");
    ZeroMemory( &pi2, sizeof(PROCESS_INFORMATION) );
    ZeroMemory( &si2, sizeof(STARTUPINFO) );
    si2.cb = sizeof(STARTUPINFO); 
    si2.hStdOutput = g_hChildStd_OUT_Wr2;
    si2.hStdError = g_hChildStd_OUT_Wr2; // also add the pipe as stderr!
    si2.dwFlags |= STARTF_USESTDHANDLES;
    assert(CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si2, &pi2));
    //read from pipe
    CloseHandle(g_hChildStd_OUT_Wr2);
    memset(chBuf, 0, BUFSIZE);
    for (;;) 
    { 
        DWORD dwRead = 0;
        DWORD bytes = 0;
        if (!PeekNamedPipe(g_hChildStd_OUT_Rd2,NULL,NULL,NULL,&bytes,NULL)) {
            //printf("Peek named pipe failed!");
            break;
        }

        if (bytes != 0) {
            if (!ReadFile( g_hChildStd_OUT_Rd2, chBuf, BUFSIZE, &dwRead, NULL)) 
            {
                printf("EOF!!\n");
                break;

            }
            else {
                chBuf[dwRead] = 0;
                printf("%s", chBuf);
            }

        } else {
            Sleep(5000);
        }

    }
    while(1) {
    Sleep(1000);
    printf("Lopp!\n");
    }
    return 0;
}

有什么提示嗎? 有沒有一種方法可以像在POSIX中一樣保持進程直到讀取其管道?

謝謝!

我認為問題不存在。

您的代碼中確實有一些問題。 許多是未成年人:您對si2和pi2進行了兩次初始化(無害),您有一個無限循環,因此您的編將永無止境(我假設您是Ctrl-C ...),您正在混合_tmain和WCHAR(應為wmainWCHAR_tmainTCHAR ),但如果您執行unicode構建,則可以。

一種更為嚴重: chBuf大小為BUFSIZE ,您chBuf可以讀取BUFSIZE字符(直到此處為止)。 但是,如果您確實讀取了BUFSIZE個字符,則dwReadBUFSIZE並且在下一行您將有緩沖區溢出

chBuf[dwRead] = 0; // buffer overflow if BUFSIZE chars have been read !

我只用:

if (!ReadFile( g_hChildStd_OUT_Rd2, chBuf, BUFSIZE - 1, &dwRead, NULL))

並且程序正常運行。

順便說一句:在關閉子進程的所有句柄之前,系統都會知道子進程(即使已終止)……並且您在pi2.hProcess也擁有該子進程的句柄。

當然,我不能使用c:\\\\myprocess.exe並使用cmd /c dir進行測試。 因此,如果上面的修復是不夠的嘗試使用同一個孩子像我一樣,因為這個問題可能來自myprocess.exe即開始用NULL hStdInput

好的,僅供參考,我想分享我的經驗以及如何解決該問題。 可能是我生成的子進程中有問題,但是從我的觀察中,如果我以非阻塞模式調用Read,那么只有在PeekNamedPipe之后,沒有什么可以阻止該進程被釋放,即使我保持對管道的引用。 我已經解決了啟動另一個線程的問題,該線程確實阻止了管道描述符上的Read,並且我失去了最后一個字節。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM