Win32, ReadFile from pipe block even after child terminated
Asked Answered
A

3

12

I have a simple program (in C) that create two child process, wait on an inherited pipe each, and put the output in a file.

Everything works well, except that after some write/read cycle on the two pipe, when the child ends, the call to ReadFile block, waiting for data on the pipe. I use the following pattern:

...
//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);
    ...
}
... 

The last call (after child process exit) block. Idea of why (and, if not, how to debug this)?

Arsenious answered 31/5, 2012 at 21:55 Comment(2)
Thanks for asking, and for answering. I have been bouncing back and forth between _popen(...) variants (which work well on my Code::Blocks-GCC environment, but not on at all on my work environment) and the CreateProcess/CreatePipe methods you use. Your implementation works great. Thanks.Underpart
thank, run across this today!Licastro
A
15

I found out the solution myself (wich actually was a coding error). I wasn't closing the parent's write handle of the pipe properly (hWrite), so, the synchronous ReadFile wasn't able to report me back the child process termination.

If somebody has the same problem, make sure you close the inheritable handle of the pipe before starting the I/O operation on that pipe (as MSDN reports, cannot find again were).

Arsenious answered 2/6, 2012 at 13:53 Comment(2)
Some helpful docs on this issue: msdn.microsoft.com/en-gb/library/windows/desktop/…Iaria
Thanks for this answer. Microsoft's own code example[1] for this is broken, but this resolved the issue for me. [1]: msdn.microsoft.com/en-us/library/windows/desktop/…Drava
R
7

You are calling ReadFile() in synchronous mode. As long as the pipe is open, ReadFile() will block waiting for more data. If you leave open the process and thread handles that CreateProcess() returns to you, that will prevent the child process from fully exiting, so the pipe may not get closed on the child end. Before entering your reading loop, close the handles that CreateProcess() returns, allowing the pipe to close properly when the child process fully terminates, and then ReadFile() can report an error back to you when it can't read from the pipe anymore. Alterntively, switch to overlapped I/O on the pipe so you can monitor the child process with WaitForSingleObject() or GetExitCodeProcess() while the loop is running so you can detect when the child process terminates regardless of the pipe state.

Robbie answered 1/6, 2012 at 21:6 Comment(3)
Actually, I cannot wait for the child process to terminate before the loop terminate. Besides, I resolved the problem myself: I wasn't closing the parent's write handle of the pipe properly, so, the synchronous ReadFile wasn't able to report me back the child process termination. Thank you anywayArsenious
@Remy, are you sure? I've never heard that holding open handles to a process will prevent Windows from closing the handles belonging to that process when it exits.Tejada
I have the same problem and the same solution - I suspect it's because, if you don't close the handle, the parent process could write to the pipe, and then read from the same pipe itself. Therefore, ReadFile must wait/the pipe must be kept open since the above (silly) case could still happen. But if no handles exist anymore, then nothing can ever write to the pipe again.Electroencephalogram
O
0

In your case all good, you had access to both processes on the pipe. If however you did not, or just wanted to interrupt the ReadFile call, then CancelSynchronousIo is your friend: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363789(v=vs.85).aspx

Ochre answered 23/6, 2016 at 14:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.