Зависание при создании процесса с перенаправленным выводом
От: Spaun2002 Россия  
Дата: 08.08.08 08:34
Оценка:
Доброго всем времени суток.
Наткнулся на проблему, и никак не могу найти решение.
Суть: из моей программы нужно перехватывать консольный вывод от дочернего процесса. Делается через Pipe. Работало все замечательно до тех пор, пока не понадобилось получать раздельно вывод в StdOutput и StdError. Для этого создал второй пайп и подсунул его в hStdError. И вот тут случилось непредвиденное. При выполнении ReadFile из пайпа виснет мое приложение (вроде как понятно — ждет пока в пайп хоть что-то будет записано). Но дочернее приложение также виснет, но уже на вызове WriteFile. И все. Намертво.
Написал воспроизводимый пример. Компилировал VS2005 и VS2008. Результат один — зависание. Ощущение, что происходит deadlock на дескрипторе пайпа. (Обидно к тому же, что функция, которая виснет при записи в пайп на стороне дочернего процесса из msvcrt называется _write_no_lock).
Может кто сталкивался с подобной проблемаой или знает пути ее решения?

вот исходный код "родительского процесса":

#include <iostream>
#include <windows.h>
#include <conio.h>

using namespace std;

char buffer[256];
char szTestExe[] = "test8.exe";    //имя файла для дочернего процесса

void main()
{
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    STARTUPINFO si;
    HANDLE hStdOutRead, hStdOutWrite;
    HANDLE hStdErrRead, hStdErrWrite;
    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
    ZeroMemory(&si, sizeof(STARTUPINFO));
    ZeroMemory(buffer, sizeof(char)*256);
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = true;
    sa.lpSecurityDescriptor = NULL;

    CreatePipe(&hStdOutRead, &hStdOutWrite, &sa, 4096);
    CreatePipe(&hStdErrRead, &hStdErrWrite, &sa, 4096);
    SetHandleInformation(hStdOutRead, HANDLE_FLAG_INHERIT, 0);
    SetHandleInformation(hStdErrRead, HANDLE_FLAG_INHERIT, 0);

    si.cb = sizeof(STARTUPINFO);
    si.wShowWindow = SW_SHOW;
    si.hStdError = hStdErrWrite;        //Если для stderr и stdout указать один
    si.hStdOutput = hStdOutWrite;        //пайп, то все работает нормально
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.dwFlags = STARTF_USESTDHANDLES;

    if (CreateProcess(szTestExe, NULL, NULL, NULL, true, 
            CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
    {
        CloseHandle(pi.hThread);
        CloseHandle(hStdErrWrite);
        CloseHandle(hStdOutWrite);

        BOOL res = false;
        DWORD dwBytesRead = 0;
        cout << "---===== starting =====---" << endl;
        do 
        {
            //Здесть происходит зависание. ReadFile не возвращает управление.
            res = ReadFile(hStdOutRead, buffer, 255, &dwBytesRead, NULL);
            if (res && dwBytesRead > 0)
            {
                buffer[dwBytesRead] = '\0';
                cout << buffer;
            }
        } while(res);
        cout << "---=========== errors ===========---" << endl;
        do 
        {
            res = ReadFile(hStdErrRead, buffer, 255, &dwBytesRead, NULL);
            if (res && dwBytesRead > 0)
            {
                buffer[dwBytesRead] = '\0';
                cout << buffer;
            }
        } while(res);

        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(hStdOutRead);
        CloseHandle(hStdErrRead);

    } else
    {
        cout << "unable to start process" << endl;
    }
    cout << "Done" << endl;
    _getch();
}


А вот для дочернего процесса:

#include <stdio.h>
#include <stdlib.h>
#define BUF_SIZE 1024
char buff[BUF_SIZE];
void main()
{
    for (int i= 0; i < BUF_SIZE; i++)
        buff[i] = (char)(rand()%(127-20))+20;
    buff[BUF_SIZE-1] = '\0';

    for (int i = 0; i < 100; i++)
    {
        fprintf(stdout, "%s %d\n", "HELLO WORLD FROM TEST", i);
        //при выводе в stderr в определенный момент происходит зависание на 
        //функции WriteFile (когда происходить flush буфера, примерно при записи 
        //4096 байт во временный буфер
        fprintf(stderr, "%s", buff);
    }
        
    fflush(stderr);
    fflush(stdout);
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.