【问题标题】:C/C++: Flush output before abnormal terminationC/C++:异常终止前刷新输出
【发布时间】:2013-08-19 15:29:14
【问题描述】:

是否需要在调用abort() 之前显式刷新输出流以避免丢失输出?

据我了解,stderr 没有缓冲,所以在输出到stderr/cerr 后调用abort 应该没问题。 stdout/cout 或者我打开的文件怎么样?

PS。我在 Linux 环境中工作(如果重要的话)。

【问题讨论】:

    标签: c++ c io abort


    【解决方案1】:

    是的,它是必需的,但不,它可能是不可能的。如果您正在从异步信号上下文中止,则调用 fflush 会调用未定义的行为。通常,如果调用abort 的原因是您在程序中检测到不一致的状态,则存在stdio 状态也被破坏的风险,因此调用fflush 是不安全的。

    一般来说,如果您由于程序无法处理的情况而终止,您应该使用exit(1),并且只有在检测到您的程序被调用时才使用abort()(没有fflush)已经有未定义的行为,

    更多细节:

    C 标准允许实现将 stdio 流作为 abort 的一部分刷新 (C11 7.22.4.1:):

    是否刷新带有未写入缓冲数据的打开流、关闭打开流或删除临时文件是实现定义的。

    但是,如果从信号处理程序调用abort,这并不能消除这种要求。因为,从实际的角度来看,如果 abort 是从中断了缓冲区处于不一致状态的 stdio 代码的信号处理程序调用的,通常不可能刷新缓冲区,因此任何尝试使用此允许的实现都可能是错误的.

    abort 的 Linux 手册页的当前版本错误地指出:

    如果 abort() 函数导致进程终止,则所有打开的流都将关闭并刷新。

    对当前行为更正确的说法是,已尝试刷新,但可能会失败或损坏您的数据。根据此线程,此错误目前正在 glibc 中修复(也许修复已经提交...?):

    http://www.sourceware.org/ml/libc-alpha/2013-05/msg00207.html

    【讨论】:

    • 是只中止刷新内核缓冲区,还是中止用户空间中的 stdio 缓冲区?
    • 我正在使用 MPI 和 OpenMP 线程编写科学代码。如果我遇到错误(通常与用户输入相关,或与一些运行时计算相关),我只想退出我的程序。我问初始问题的原因是我希望在程序终止之前刷新包含信息和错误描述的日志文件。所以从你的回答来看,我不需要使用abortexit(EXIT_FAILURE)就足够了吗?
    • @user2052436:就可观察到的行为而言,没有内核缓冲区之类的东西。
    • @user2052436,是的,exit(EXIT_FAILURE) 应该足以捕获用户错误。 abort 应该只用于更严重的情况。例如,如果您检测到您的应用程序完全耗尽内存。
    • @JensGustedt:我认为abortexit(1) 都是不良行为,因为内存不足。这里真的没有必要更喜欢abort,因为程序处于调用exit仍然安全的状态,但abort的恶意可能会稍微小一些,因为调用代码可能会捕获SIGABRT和@987654341 @ 退出因内存不足而中止的错误代码。 :-) 如果你在这样的非 UB 情况下使用abort,我认为最好先调用fflush(0)
    【解决方案2】:

    Stdout 是缓冲的,例如,您使用 ofstream 打开的文件也是如此。您必须使用刷新操纵器显式刷新它们

    【讨论】:

    • 虽然这在大多数情况下都是正确的,但可以在没有缓冲的情况下打开文件,我相信甚至有可能得到一个无缓冲的stdout一些诡计。
    • 只需在main 的开头使用setvbufsetbuf 即可获得无缓冲的stdout
    猜你喜欢
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    相关资源
    最近更新 更多