boo*_*hoo 7 c linux stdio eintr fclose
所以我正在研究fclose manpage,我的结论是,如果fclose被某些信号中断,根据联机帮助页有没有办法恢复......?我错过了一些观点吗?
通常,使用无缓冲的POSIX功能(打开,关闭,写入等),总有一种方法可以通过重新启动呼叫来从信号中断(EINTR)中恢复; 相反,缓冲调用的文档说明在fclose尝试失败后,另一个尝试有未定义的行为...没有关于如何恢复的提示.如果信号中断fclose,我只是"不幸"吗?数据可能会丢失,我无法确定文件描述符是否实际关闭.我知道缓冲区已被释放,但文件描述符呢?想想大规模的应用程序同时使用很多fd的,并且如果fd没有被正确释放会遇到问题 - >我会假设必须有一个CLEAN解决方案来解决这个问题.
所以我们假设我正在编写一个库,并且不允许使用sigaction和SA_RESTART并且发送了大量信号,如果fclose被中断,我该如何恢复?fclose与EINTR失败后,在循环(而不是fclose)中调用close是不是一个好主意?fclose的文档根本没有提到文件描述符的状态; 但是,UNDEFINED并不是很有帮助...如果fd关闭并且我再次调用close,可能会发生奇怪的难以调试的副作用,所以我宁愿忽略这种情况,因为做了错误的事情......然后再次,那里没有无限数量的文件描述符可用,资源泄漏是某种错误(至少对我而言).
当然我可以检查fclose的一个具体实现,但我不相信有人设计了stdio并且没有想到这个问题?它只是文档是坏的还是这个功能的设计?
这个角落案件真的让我感到困惑:(
EINTR 和 close()事实上,close()不仅与fclose().
POSIX 声明close()返回EINTR,这通常意味着应用程序可以重试调用。然而,事情在 linux 中更为复杂。请参阅有关 LWN 的这篇文章以及这篇文章。
[...]POSIXEINTR语义在 Linux 上是不可能的。传递给的文件描述符close()在系统调用处理的早期被取消分配,并且相同的描述符可能在时间close()返回时已经分发给另一个线程。
这篇博文和这个答案解释了为什么close()使用EINTR. 因此,在 Linux 中,如果close()使用EINTR(或EINPROGRESS)失败,您将无法做任何有意义的事情。
另请注意,这close()在 Linux中是异步的。例如,有时umount可能会EBUSY在关闭文件系统上最后打开的描述符后立即返回,因为它尚未在内核中发布。在此处查看有趣的讨论:第 1页,第 2 页。
EINTR 和 fclose()POSIX 声明为fclose():
在调用 之后
fclose(),对流的任何使用都会导致未定义的行为。无论调用是否成功,流都应与文件解除关联,
setbuf()或setvbuf()函数设置的任何缓冲区都应与流解除关联。如果关联的缓冲区是自动分配的,则应取消分配。
我相信这意味着即使close()失败,也fclose() 应该释放所有资源并且不会产生泄漏。至少对于glibc和uclibc实现是这样。
fflush()之前打电话fclose()。
由于您无法确定fclose()在调用fflush()or时是否失败,因此close()您必须在fflush()之前显式调用fclose()以确保用户空间缓冲区已成功发送到内核。
之后不要重试EINTR。
如果fclose()失败EINTR,则不能重试close(),也不能重试fclose()。
fsync()有需要就打电话。
fsync()或。fdatasync()fclose() EINTRfrom fclose()。如果fflush()与fsync()成功,fclose()有失败EINTR,没有数据丢失和出现无泄漏。
你也应该确保FILE对象不之间使用fflush()和fclose()调用从另一个线程2。
[1] 请参阅“关于 Fsync() 的一切你一直想知道的”文章,其中解释了为什么fsync()也可能是异步操作。
[2] 可以flockfile()先调用fflush()和fclose()。它应该fclose()正确工作。