【问题标题】:Should I always close stdout explicitly?我应该始终明确关闭标准输出吗?
【发布时间】:2015-11-07 23:03:09
【问题描述】:

我正在尝试集成一个小型 Win32 C++ 程序,该程序从标准输入读取并将解码结果(〜128 KB)写入输出流。

我用

将整个输入读入缓冲区
while (std::cin.get(c)) { }

在我将整个输出写入标准输出之后。

当我从命令行运行应用程序时一切正常,例如test.exe < input.bin > output.bin,但是这个小应用程序应该从 Python 运行。

我希望应该使用 Python subprocess.communicate,文档说:

与进程交互:将数据发送到标准输入。从标准输出读取数据并 stderr,直到到达文件结尾。等待进程终止。

所以communicate() 将等到文件结束后再等待我的应用程序完成 - 我的应用程序退出时应该发生 EOF 吗?还是我应该明确地做 fclose(stderr) 和 fclose(stdout)?

【问题讨论】:

  • 你不应该明确释放任何你没有明确获得的资源,除非你有特定的文档告诉你。不遵守这一点是难以解决问题的秘诀。
  • 现在我明白了——子进程为管道的另一端获取自己的句柄/描述符,至少在子进程终止时关闭。
  • 不相关:要模拟test.exe < input.bin > output.bin shell 命令,您可以使用subprocess.check_call('test', stdin=open('input.bin'), stdout=open('stdout.bin', 'w')),即不需要.communicate()

标签: python c++ windows pipe subprocess


【解决方案1】:

不要关闭标准输出

在一般情况下,它实际上是错误的,因为可以使用atexit() 注册一个尝试写入标准输出的函数,如果标准输出关闭,这将中断。

当进程终止时,操作系统会自动关闭所有句柄。这包括标准输出,因此您无需手动关闭它。

(从技术上讲,C++ 运行时normally 会在操作系统有机会参与之前尝试刷新和关闭所有 C++ 流,但操作系统绝对必须关闭运行时的任何句柄,对于whatever reason,未命中。)

在特殊情况下,关闭标准流(例如,在守护进程时)可能很有用,但应该非常小心。重定向到或从空设备(Unix 上的/dev/null,Windows 上的nul)通常是一个好主意,这样期望与这些流交互的代码仍然可以工作。在 Unix 上,这是通过 freopen(3) 完成的; Windows 有 an equivalent function,但它是 POSIX API 的一部分,可能不适用于标准 Windows I/O。

【讨论】:

  • 我会稍微修改一下 - 如果您有特定的原因,关闭标准输出可能是可以接受的,即您需要在没有实际退出的情况下发出数据结束的信号。当然,您必须小心确保程序在这样做之后不再使用 stdout。
  • @HarryJohnston:在某些特殊情况下可能是合理的,但您需要仔细评估您可能正在使用的任何库或其他代码。例如,在某些系统上,当进程通过信号(“Terminated”、“Killed”、“Segmentation Fault”等)终止时,您可能会得到输出,我不确定这是否需要功能性 stdout/stderr,或者如果没有标准输出,它的行为方式。
  • 您可以使用 /dev/null 关闭然后重新打开 3 个 std 句柄,以便 0、1、2 路由到 null,就像我们如何守护进程一样。
  • @Calvin:没有理由在 Unix 上这样做(因为 dup2(2) 为你做了所有这些),我不确定它是否适用于 Windows。
  • 信号在 Windows 上应该不是问题,前提是您没有注册任何默认情况下禁用的信号处理程序。但是你肯定要小心第三方库。
猜你喜欢
  • 2018-03-06
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 1970-01-01
  • 2012-06-10
  • 2018-08-29
  • 1970-01-01
  • 2010-11-16
相关资源
最近更新 更多