草庐IT

c - fclose 不可能的正确错误处理(根据联机帮助页)?

coder 2023-06-18 原文

所以我研究了 fclose 联机帮助页很长一段时间,我的结论是如果 fclose 被某些信号中断,根据联机帮助页没有办法恢复...?我错过了什么吗?

通常,对于无缓冲的 POSIX 函数(打开、关闭、写入等),总有一种方法可以通过重新启动调用来从信号中断 (EINTR) 中恢复;相比之下,缓冲调用的文档指出,在 fclose 尝试失败后,另一次尝试具有未定义的行为......没有关于如何恢复的提示。如果信号中断 fclose,我只是“不走运”吗?数据可能会丢失,我不能确定文件描述符是否真的关闭了。我知道缓冲区被释放了,但是文件描述符呢? 想想同时使用大量 fd 的大型应用程序,如果 fd 没有被正确释放就会遇到问题 -> 我认为必须有一个干净的解决方案来解决这个问题。

那么假设我正在编写一个库并且它不允许使用 sigaction 和 SA_RESTART 并且发送了很多信号,如果 fclose 被中断我该如何恢复? 在 fclose 因 EINTR 失败后在循环中调用 close(而不是 fclose)是个好主意吗? fclose 的文档根本没有提到文件描述符的状态; UNDEFINED 虽然不是很有帮助......如果 fd 关闭并且我再次调用 close,可能会出现奇怪的难以调试的副作用,所以我自然而然地宁愿忽略这种情况作为做错事...话又说回来,没有无限数量的可用文件描述符,资源泄漏是某种错误(至少对我而言)。

当然,我可以检查 fclose 的一个特定实现,但我不敢相信有人设计了 stdio 却没有考虑这个问题?是文档不好还是这个功能的设计不好?

这个极端情况真的让我很烦 :(

最佳答案

EINTRclose()

其实close()也有问题,不仅仅是fclose()

POSIX 指出 close()返回 EINTR,这通常意味着应用程序可能会重试调用。然而,在 Linux 中事情要复杂得多。参见 this article在 LWN 上还有 this post .

[...] the POSIX EINTR semantics are not really possible on Linux. The file descriptor passed to close() is de-allocated early in the processing of the system call and the same descriptor could already have been handed out to another thread by the time close() returns.

This blog postthis answer解释为什么重试 close() 失败并返回 EINTR 不是一个好主意。因此在 Linux 中,如果 close()EINTR(或 EINPROGRESS)而失败,您将无能为力。

另请注意,close() 在 Linux 中是异步的。例如,有时 umount 可能会在关闭文件系统上最后打开的描述符后立即返回 EBUSY,因为它尚未在内核中释放。在此处查看有趣的讨论:page 1 , page 2 .


EINTRfclose()

fclose() 的 POSIX 状态:

After the call to fclose(), any use of stream results in undefined behavior.

Whether or not the call succeeds, the stream shall be disassociated from the file and any buffer set by the setbuf() or setvbuf() function shall be disassociated from the stream. If the associated buffer was automatically allocated, it shall be deallocated.

我相信这意味着即使 close() 失败,fclose() 应该 释放所有资源并且不会产生泄漏。至少对于 glibc 是正确的和 uclibc实现。


可靠的错误处理

  • fclose() 之前调用 fflush()

    由于您无法确定 fclose() 在调用 fflush()close() 时是否失败,因此您必须明确地在 fclose() 之前调用 fflush() 以确保用户空间缓冲区已成功发送到内核。

  • EINTR 后不要重试。

    如果 fclose()EINTR 失败,您不能重试 close() 也不能重试 fclose()

  • 如果需要,调用 fsync()

    • 如果您关心数据完整性,您应该在调用 fclose() 之前调用 fsync()fdatasync() 1 .
    • 如果不这样做,请忽略 fclose() 中的 EINTR

注意事项

  • 如果 fflush()fsync() 成功并且 fclose() 失败并返回 EINTR没有数据丢失并且没有发生泄漏

  • 您还应确保 FILE 对象未在来自另一个线程的 fflush()fclose() 调用之间使用2.


[1] 参见 "Everything You Always Wanted to Know About Fsync()"解释为什么 fsync() 也可能是异步操作的文章。

[2] 您可以在调用fflush()fclose() 之前调用flockfile()。它应该与 fclose() 一起正确工作。

关于c - fclose 不可能的正确错误处理(根据联机帮助页)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31527706/

有关c - fclose 不可能的正确错误处理(根据联机帮助页)?的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  4. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  5. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  6. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  7. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  8. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  9. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

  10. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

随机推荐