Win32, ReadFile из блока труб даже после того, как ребенок завершен

У меня есть простая программа (в C), которая создает два дочерних процесса, каждый раз наследует унаследованный канал и помещает вывод в файл.

Все работает хорошо, за исключением того, что после некоторого цикла записи/чтения на двух каналах, когда заканчивается ребенок, вызов блока ReadFile, ожидая данных на трубе. Я использую следующий шаблон:

...
//create pipe1
CreatePipe(&hReadDup,&hWrite,&saAttr,0);
DuplicateHandle(GetCurrentProcess(),hReadDup,GetCurrentProcess(),&hRead,0,FALSE,DUPLICATE_SAME_ACCESS);
CloseHandle(hReadDup);


si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hWrite;   

CreateProcess(  NULL,
        const_cast<LPWSTR>(cmd2.c_str()), //the command to execute
        NULL,
        NULL,
        TRUE,
        0,
        NULL,
        NULL,
        &si, //si.
        &pi
    );

...
CloseHandle(hWrite); // EDIT: this was the operation not properly done!

while(cont){
    ...
    cont = ReadFile(hRead,buf,50, &actual,NULL);
    ...
}
... 

Последний вызов (после выхода из дочернего процесса). Идея почему (и, если нет, как отладить это)?

Ответ 1

Я сам выяснил решение (которое действительно было ошибкой кодирования). Я не закрывал родительский дескриптор записи правильно (hWrite), поэтому синхронный ReadFile не смог сообщить мне о завершении дочернего процесса.

Если у кого-то такая же проблема, убедитесь, что вы закрыли наследуемый дескриптор канала, прежде чем запускать операцию ввода-вывода на этом канале (поскольку отчеты MSDN не могут найти их снова).

Ответ 2

Вы вызываете ReadFile() в синхронном режиме. Пока труба открыта, ReadFile() блокирует ожидание большего количества данных. Если вы оставите открытым обработчик процессов и потоков, возвращаемый вам CreateProcess(), это предотвратит полное завершение дочернего процесса, поэтому канал может не закрыться на дочернем конце. Перед тем, как войти в цикл чтения, закройте дескрипторы, возвращаемые CreateProcess(), позволяя правильному закрытию канала, когда дочерний процесс полностью завершается, а затем ReadFile() может сообщить об ошибке вам, когда он больше не может читать из канала, Альтернативно, переключитесь на перекрывающиеся входы/выходы на трубе, чтобы вы могли контролировать дочерний процесс с помощью WaitForSingleObject() или GetExitCodeProcess() во время работы цикла, чтобы вы могли обнаружить, когда дочерний процесс завершается независимо от состояния канала.

Ответ 3

В вашем случае все хорошо, у вас был доступ к обоим процессам на трубе. Если, однако, вы этого не сделали или просто хотели прервать вызов ReadFile, тогда CancelSynchronousIo является вашим другом: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363789(v=vs.85).aspx