对fclose进行适当的错误处理是不可能的(根据联机帮助页)?

前端之家收集整理的这篇文章主要介绍了对fclose进行适当的错误处理是不可能的(根据联机帮助页)?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
所以我正在研究fclose manpage,而我的结论是,如果fclose被某些信号中断,根据联机帮助页有没有办法恢复……?我错过了一些观点吗?

通常,使用无缓冲的POSIX功能(打开,关闭,写入等),总有一种方法可以通过重新启动呼叫来从信号中断(EINTR)中恢复;相反,缓冲调用的文档说明在fclose尝试失败后,另一次尝试有未定义的行为…没有关于如何恢复的提示.如果信号中断fclose,我只是“不幸”吗?数据可能会丢失,我无法确定文件描述符是否实际关闭.我知道缓冲区已被释放,但文件描述符呢?
考虑大量使用fd的批量应用程序,如果没有正确释放fd,会遇到问题 – >我认为必须有一个CLEAN解决方案来解决这个问题.

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

当然我可以检查fclose的一个具体实现,但我不相信有人设计stdio并且没有考虑这个问题?它只是文档是坏的还是这个函数的设计?

这个角落案件真的让我烦恼:(

解决方法

EINTR和关闭()

事实上,close()也存在问题,而不仅仅是fclose().

POSIX声明close()返回EINTR,这通常意味着应用程序可能会重试该呼叫.但是Linux中的事情比较复杂.见LWN上的this articlethis post.

[...]@H_403_23@ the POSIX EINTR@H_403_23@ semantics are not really possible on Linux. The file descriptor passed to close()@H_403_23@ 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()@H_403_23@ returns.

This blog postthis answer解释了为什么用EINTR重试close()失败并不是一个好主意.所以在Linux中,如果close()因EINTR(或EINPROGRESS)失败,你就无能为力.

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

EINTR和fclose()

POSIX指出fclose()

After the call to fclose()@H_403_23@,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()@H_403_23@ or setvbuf()@H_403_23@ function shall be disassociated from the stream. If the associated buffer was automatically allocated,it shall be deallocated.

我相信这意味着即使close()失败,fclose()也应该释放所有资源并且不会产生泄漏.至少对于glibcuclibc实现来说这是真的.

可靠的错误处理

>在fclose()之前调用fflush().

由于在调用fflush()或close()时无法确定fclose()是否失败,因此必须在fclose()之前显式调用fflush()以确保成功将用户空间缓冲区发送到内核.
>不要在EINTR之后重试.

如果fclose()使用EINTR失败,则无法重试close(),也无法重试fclose().
>如果需要,请调用fsync().

>如果您关心数据完整性,则应在调用fclose()1之前调用fsync()或fdatasync().
>如果不这样做,只需忽略fclose()中的EINTR即可.

笔记

>如果fflush()和fsync()成功并且fclose()因EINTR而失败,则不会丢失任何数据且不会发生泄漏.
>您还应确保在来自另一个线程2的fflush()和fclose()调用之间不使用FILE对象.

[1]参见“Everything You Always Wanted to Know About Fsync()”文章,该文章解释了为什么fsync()也可能是异步操作.

[2]你可以在调用fflush()和fclose()之前调用flockfile().它应该正确使用fclose().

猜你在找的C&C++相关文章