【问题标题】:Stdout/stderr file for child process empty, FILE_FLAG_NO_BUFFERING not working子进程的标准输出/标准错误文件为空,FILE_FLAG_NO_BUFFERING 不起作用
【发布时间】:2014-07-24 23:11:43
【问题描述】:

我正在尝试捕获子进程的输出(stdout/stderr),特别是如果它异常退出,我可能会得到一些有用的错误输出。

我创建了一个输出文件,并将这个(和STARTF_USESTDHANDLES)设置在我随后传递给CreateProcess()STARTUPINFO 结构上。

现在,对于我的子进程中的不同操作,我得到以下行为:

(1) 无冲洗

printf("Hello world!\n");

结果:在子级从父级终止后(通过TerminateProcess):文件中没有输出。

(2) 在每次printf 调用后使用fflsuh()

printf("Hello world!\n");
fflush(stdout);

结果:在子级从父级终止后(通过TerminateProcess):“Hello World!” (如预期)

(3)异常终止

printf("Hello world!\n");
int *p = NULL; *p = 5; // Access violation

结果:文件中没有输出。

我可以尝试在每个printf() 之后添加fflush() 调用(糟糕!),或者尝试获得TerminateProcess() 的替代方法,以确保首先关闭文件句柄。但这对异常退出无济于事——这是首先要捕获 stdout/stderr 的要点。

我尝试的另一件事是创建带有FILE_FLAG_NO_BUFFERING 标志集的文件,但我的尝试不起作用 - CreateFile() 失败(错误 87“参数不正确”)。知道我做错了什么吗?或者是否有其他方法可以实现这一目标?

我已经为 CreateFile() dwFlagsAndAttributes 值尝试了 3 种不同的选项,结果如下。

  • FILE_ATTRIBUTE_NORMAL - 文件创建正常,但出现上述行为(因此我错过了异常终止的数据)。

  • FILE_FLAG_NO_BUFFERINGFILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING - CreateFile() 失败,GetLastError = 87 和 FormatMessage 返回“参数不正确”。我只是在这里错误地使用了标志吗?还是我的文件系统不支持此选项?

这是我用来创建输出文件和子进程的代码。我已经在下面标记了我已经为 CreateFile() dwFlagsAndAttributes 值尝试了几个不同的选项。

SECURITY_ATTRIBUTES security = {sizeof(SECURITY_ATTRIBUTES), NULL, true}; // Allow the handle to be inherited by child process
HANDLE myfile = CreateFile(myfilename,
                           FILE_APPEND_DATA,
                           FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
                           &security,
                           OPEN_ALWAYS,
                           FILE_FLAG_NO_BUFFERING, // I've tried 3 different things here - see above
                           NULL);

STARTUPINFO startupInfo = {0};
startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
startupInfo.wShowWindow = SW_HIDE;
startupInfo.hStdError = myfile;
startupInfo.hStdOutput = myfile;

PROCESS_INFORMATION processInfo = {0};

CreateProcess(NULL,
              executable,
              NULL, NULL,
              true, // Allow stdout/err file handle to be inherited
              0, NULL, NULL,
              &startupInfo,
              &processInfo))
CloseHandle(myfile); // The child owns this now

感谢您的帮助!

【问题讨论】:

  • 使用 FILE_FLAG_NO_BUFFERING 选项时存在对齐约束。请参阅msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx 一种推荐的解决方案是使用 VirtualAlloc 来分配缓冲区。虽然这不能解释为什么你会在 CreateFile 中收到错误。
  • 其他网站提到访问参数也可能是原因。将 FILE_APPEND_DATA 替换为 GENERIC_READ | 会发生什么? GENERIC_WRITE?
  • 如果您想通过 CRT 禁用缓冲,请致电 setvbuf(stdout, NULL, _IONBF, 0)。这大致相当于在每次输出调用后调用fflush
  • FILE_FLAG_NO_BUFFERING 标志用于当您担心操作系统可能崩溃或计算机可能会断电时。如果您只是担心进程崩溃,则没有必要。您需要按照 Igor 的建议关闭 CRT 缓冲。
  • 感谢 Igor 和 Harry - 删除 NO_BUFFERING 标志并按照建议使用 setvbuf 似乎有效。我仍然没有从异常中得到任何输出,但我认为这是因为我得到了一个 Windows“程序已停止工作”错误对话框,所以这是一个单独的问题。

标签: c++ windows


【解决方案1】:

感谢 Igor & Harry 在 cmets 中提出这种方法。

  • 不要使用FILE_FLAG_NO_BUFFERING 标志。这仅适用于您需要直接硬件控制的情况。
  • 在子进程开始时调用setvbuf(stdout, NULL, _IONBF, 0) 大致相当于在每次printf 调用之后调用fflush。也可以致电setvbuf 获取stderr

【讨论】:

    猜你喜欢
    • 2013-02-16
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 2022-12-14
    • 2019-10-17
    • 1970-01-01
    相关资源
    最近更新 更多