VC++ ReadFile 在读取关闭的匿名管道时意外阻塞
我正在尝试创建一个运行任何 exe 命令的子进程,并通过匿名管道将其所有 stdio 和 stderr 重定向到我的父进程。但是,当我的父进程在子进程终止后尝试在匿名管道的 READ 端执行 ReadFile() 时,它只是阻塞而不是返回错误。
这是代码:
#include "windows.h"
//==================================================
void createChildPipes(PHANDLE phRead, PHANDLE phWrite){
SECURITY_ATTRIBUTES sa={sizeof(SECURITY_ATTRIBUTES) ,NULL,TRUE};
if ( !CreatePipe(phRead, phWrite, &sa, 2048) ) { //... }
}
//==================================================
void setupStartupInfo(LPSTARTUPINFO lpsi, HANDLE hStdOutput, HANDLE hStdError) {
lpsi->cb = sizeof(STARTUPINFO);
lpsi->lpReserved=NULL;
lpsi->lpDesktop=NULL;
lpsi->lpTitle=NULL;
lpsi->dwX=0;
lpsi->dwY=0;
lpsi->dwXSize=200;
lpsi->dwYSize=500;
lpsi->dwFlags=STARTF_USESTDHANDLES;
lpsi->cbReserved2=0;
lpsi->lpReserved2=NULL;
lpsi->hStdInput=GetStdHandle(STD_INPUT_HANDLE);
lpsi->hStdError= hStdError;
lpsi->hStdOutput=hStdOutput;
}
//==================================================
void createChildProcess(PHANDLE phOutRead, PHANDLE phOutWrite, PHANDLE phErrRead, PHANDLE phErrWrite) {
TCHAR name[]=_T("cl.exe");
createChildPipes(phOutRead, phOutWrite);
STARTUPINFO si;
setupStartupInfo(&si, *phOutWrite, *phOutWrite);
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, name, NULL, NULL, true, 0, NULL, NULL, &si, &pi)) { //...}
}
//==================================================
void _tmain(int argc, _TCHAR* argv[]){
HANDLE hOutRead, hOutWrite, hErrRead, hErrWrite;
createChildProcess(&hOutRead, &hOutWrite, &hErrRead, &hErrWrite) ;
char buf[10];
BOOL readState;
for (;;) {
DWORD dwBytesRead;
memset(buf, '\0', sizeof(buf));
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , &dwBytesRead, NULL);
printf("%s", buf);
if (!readState)
break;
}
}
这就是我的代码正在做的事情。我的 _tmain() 创建一个子进程(我使用 VC++ cl.exe 命令作为测试)并将其 stdio 和 stderr 重定向到匿名管道的写入句柄。我的父进程从同一管道的读取句柄中读取。
这些由我的 _tmain() 打印,显示管道可以跨父子进程进行通信。如果我们在命令行中键入不带任何参数的 cl.exe,这些就是我们期望看到的内容。请注意 cl.exe 的特殊行为,前两行来自 cl.exe 的 stderr,最后一行来自 stdout。
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
现在关于问题,行:
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , &dwBytesRead, NULL);
in _tmain() 在子 cl.exe 进程终止后阻塞。但是,我期望 ReadFile() 调用返回 ERROR_BROKEN_PIPE 错误状态并退出父循环,而不是阻止 ReadFile() 调用。
为什么 ReadFile() 在读取匿名管道时会阻塞?
I am trying to create a child process running any exe command and redirect all its stdio and stderr to my parent process through an anonymous pipe. But when my parent process tries to do a ReadFile() on the READ end of the anonymous pipe after the child has terminated, it just blocks instead of returning an error.
Here is the code:
#include "windows.h"
//==================================================
void createChildPipes(PHANDLE phRead, PHANDLE phWrite){
SECURITY_ATTRIBUTES sa={sizeof(SECURITY_ATTRIBUTES) ,NULL,TRUE};
if ( !CreatePipe(phRead, phWrite, &sa, 2048) ) { //... }
}
//==================================================
void setupStartupInfo(LPSTARTUPINFO lpsi, HANDLE hStdOutput, HANDLE hStdError) {
lpsi->cb = sizeof(STARTUPINFO);
lpsi->lpReserved=NULL;
lpsi->lpDesktop=NULL;
lpsi->lpTitle=NULL;
lpsi->dwX=0;
lpsi->dwY=0;
lpsi->dwXSize=200;
lpsi->dwYSize=500;
lpsi->dwFlags=STARTF_USESTDHANDLES;
lpsi->cbReserved2=0;
lpsi->lpReserved2=NULL;
lpsi->hStdInput=GetStdHandle(STD_INPUT_HANDLE);
lpsi->hStdError= hStdError;
lpsi->hStdOutput=hStdOutput;
}
//==================================================
void createChildProcess(PHANDLE phOutRead, PHANDLE phOutWrite, PHANDLE phErrRead, PHANDLE phErrWrite) {
TCHAR name[]=_T("cl.exe");
createChildPipes(phOutRead, phOutWrite);
STARTUPINFO si;
setupStartupInfo(&si, *phOutWrite, *phOutWrite);
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, name, NULL, NULL, true, 0, NULL, NULL, &si, &pi)) { //...}
}
//==================================================
void _tmain(int argc, _TCHAR* argv[]){
HANDLE hOutRead, hOutWrite, hErrRead, hErrWrite;
createChildProcess(&hOutRead, &hOutWrite, &hErrRead, &hErrWrite) ;
char buf[10];
BOOL readState;
for (;;) {
DWORD dwBytesRead;
memset(buf, '\0', sizeof(buf));
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , &dwBytesRead, NULL);
printf("%s", buf);
if (!readState)
break;
}
}
This is what my code is doing. My _tmain() creates a child process (I am using the VC++ cl.exe command as a test) and redirects its stdio and stderr to the write HANDLE of an anonymous pipe. My parent process reads from the read HANDLE of the same pipe.
These are printed by my _tmain() showing that the pipe can communicate across the parent-child processes. These are what we expect to see if we type cl.exe in the command line without any arguments. Note the peculiar behaviour of cl.exe that the first 2 lines are from the stderr of cl.exe and the last line is from the stdout.
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
usage: cl [ option... ] filename... [ /link linkoption... ]
Now about the problem, the line:
readState=ReadFile(hOutRead, buf, sizeof(buf)-2 , &dwBytesRead, NULL);
in _tmain() blocks after the child cl.exe process terminated. But, I am expecting the ReadFile() call to return with an ERROR_BROKEN_PIPE error status and exit the parent loop instead of blocking the ReadFile() call.
Why the ReadFile() blocks when reading an anonymous pipe?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您忘记关闭父进程中的管道句柄,所以管道还没有完全关闭。
You forgot to close the pipe handles in the parent process, so the pipe is not completely closed yet.