【发布时间】:2017-03-08 12:59:44
【问题描述】:
问题:
在使用 EINTR 或 EIO 失败的 close() 系统调用之后,未指定文件是否已关闭。 (http://pubs.opengroup.org/onlinepubs/9699919799/) 在多线程应用程序中, 重试关闭可能会关闭其他线程打开的无关文件。不重试关闭可能会导致无法使用的打开文件描述符堆积。一个干净的解决方案可能涉及在新关闭的文件描述符上调用 fstat() 和一个相当复杂的锁定机制。 此外,使用单个互斥锁序列化所有打开/关闭/接受/...调用可能是一种选择。
这些解决方案没有考虑到 库函数可能会以不可控的方式自行打开和关闭文件,例如 std::thread::hardware_concurrency() 的某些实现会在 /proc 文件系统中打开文件。
[file.streams] C++ 标准部分中的文件流不是一个选项。
是否有一种简单可靠的机制可以在存在多个线程的情况下关闭文件?
编辑:
常规文件: 虽然大多数情况下不会累积不可用的打开文件描述符,但有两个条件可能会触发问题: 1. 某些恶意软件高频发射的信号 2. 在刷新缓存之前断开连接的网络文件系统。
Sockets:根据 Stevens/Fenner/Rudoff,如果在引用已连接套接字的文件描述符上设置了套接字选项 SO_LINGER,并且在 close() 期间,定时器在 FIN-ACK 关闭序列完成之前结束,关闭() 作为通用程序的一部分失败。 Linux 不会显示这种行为,但是,FreeBSD 会显示,并且还会将 errno 设置为 EAGAIN。据我了解,在这种情况下,未指定文件描述符是否无效。用于测试行为的 C++ 代码:http://www.longhaulmail.de/misc/close.txt 在我看来,那里的测试代码输出看起来像是 FreeBSD 中的竞争条件,如果不是,为什么不呢?
在调用 close() 期间可能会考虑阻塞信号。
【问题讨论】:
-
@VictorDyachenko POSIX 说 fd 的状态在 EINTR 和 EIO 上都未指定。
-
在 Linux 上,即使“失败”,关闭也会无条件地使其参数文件描述符无效。 Linus 在邮件列表中提到过一次。
-
另请参阅Not checking
close()'s return value — how serious really?、How to close a file?、System call interrupted by a signal still has to be completed 以及毫无疑问的其他人(我找不到我期望找到的那个)。基本上,你被卡住了。您必须将文件描述符视为已关闭 - 永远不要再次使用它,除非它由文件描述符创建函数返回(在这种情况下,您可以放心地假设关闭正常)。
标签: c++ multithreading unix freebsd