【问题标题】:ReadFile hanging on pipe readingReadFile 挂在管道读取上
【发布时间】:2019-04-23 11:15:15
【问题描述】:

我正在使用CreateProcess() 运行cmd.exe(没有向用户显示物理窗口)并且需要处理输出。为此,我决定使用CreatePipe()

我目前遇到一个问题,即我的所有输出都被读取和处理,但对ReadFile() 的最终调用挂起。四处搜索告诉我,我需要在读取之前关闭管道的写入端,这是解决此问题的方法,但我已经这样做了,但问题仍然存在。

这是我的代码:

// sw -> path to cmd.exe, ptr is the command
ok = CreateProcess(sw, ptr, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo);
CloseHandle(hStdInPipeRead);
char buf[1024 + 1] = {};
DWORD dwRead = 0;
DWORD dwAvailable = 0;
DWORD testRes;
CloseHandle(hStdOutPipeWrite);
ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
// String handling for initial read omitted for clarity
string temp = buf;
bool holdOff = false;

while (ok == TRUE)
{
    buf[dwRead] = '\0';
    OutputDebugStringA(buf);
    puts(buf);
    // ReadFile gets all the correct output from cmd here but it also hangs on the very last call. How to fix?
    ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    temp = buf;
    // handle and store output
    break;
}
CloseHandle(hStdOutPipeRead);
CloseHandle(hStdInPipeWrite);

【问题讨论】:

  • 如果没有 swptr 值,很难推断出 cmd 的作用。您的管道在cmd 退出之前一直有效。
  • 为您创建 2 个管道对(4 个手柄)而不是 1 对(2 个手柄)?并从自身端使用异步管道端
  • 您没有显示设置管道或 CreateProcess 参数的代码。请提供minimal reproducible example
  • @RemyLebeau - 可以假设这通常是来自stackoverflow.com/a/55718264/6401656的复制粘贴
  • 并且需要理解 - 只有当另一端的 所有 句柄都将关闭时,读取文件才会失败(使用 ERROR_BROKEN_PIPE)。因为这你需要关闭 hStdOutPipeWrite 并且它重复的句柄将在 cmd 退出时关闭。所以 cmd 在你的情况下不会退出

标签: c++ winapi


【解决方案1】:

如果你设置SECURITY_ATTRIBUTES.bInheritHandle = true,子进程会继承管道的句柄,你关闭的管道的写句柄只是父进程的,子进程中还有一个句柄(子进程的stdout),它没有' t 已在 cihld 进程中关闭,Readfile 失败并仅在所有写句柄都关闭或发生错误时返回。

另外,Anonymous Pipe Operations

不支持异步(重叠)读写操作 通过匿名管道(由CreatePipe 创建)。

所以,如果你仍然需要向子进程发送命令来执行cmd,你应该把ReadFile放在一个线程中。 如果您不再需要,请终止子进程:

TerminateProcess(ProcessInfo.hProcess,0);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
// String handling for initial read omitted for clarity
string temp = buf;
bool holdOff = false;
while (ok == TRUE)
{
    buf[dwRead] = '\0';
    OutputDebugStringA(buf);
    puts(buf);
    // ReadFile gets all the correct output from cmd here but it also hangs on the very last call. How to fix?
    ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    temp = buf;
    // handle and store output
    break;
}
CloseHandle(hStdOutPipeRead);
CloseHandle(hStdInPipeWrite);

【讨论】:

  • 匿名管道不支持异步(重叠)读写操作。 - 这是绝对错误的。管道当然支持异步模式。管道有名称还是为空 - 不影响这一点。更正确的说法是,通过具体 api CreatePipe 创建的管道是同步的。 TerminateProcess - 当然错了,不需要打电话。
  • 这意味着您不能将ReadFileEx 函数与匿名管道一起使用。此外,当这些函数与匿名管道一起使用时,ReadFile 的 lpOverlapped 参数将被忽略。
  • 不,你错了。这可以创建异步匿名管道。只需要使用不是CreatePipe 而是另一个api。当您说 ReadFile 的 lpOverlapped 参数被忽略时,您也犯了错误 - 即使对于同步文件,它也不会被忽略。 ReadFileEx 当然也可以用于同步文件
  • 所以你所说的所有错误:1. ReadFile never 的 lpOverlapped 参数被忽略。适用于任何文件模式。 2 ReadFileEx 可以一直使用,即使是同步文件。 3.匿名管道不是一些特殊的管道类型 - 只存在管道和所有。哪个名称有管道(特殊情况为空名称) - 这不会影响同步或异步 io 模式
  • 关于ReadFileEx - 它不能只用于绑定到iocp端口的文件,因为apc proc和iocp互斥
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多