POSIX / UNIX:如何可靠地closures文件描述符

问题:

在closures()系统调用与EINTR或EIO失败之后,未指定该文件是否已closures。 ( http://pubs.opengroup.org/onlinepubs/9699919799/ )在multithreading应用程序中,重试closures可能会closures由其他线程打开的无关文件。 不重试closures可能会导致无法使用的打开文件描述符堆积。 干净的解决scheme可能涉及对新近closures的文件描述符调用fstat()以及一个相当复杂的locking机制。 另外,使用单个互斥锁序列化所有打开/closures/接受/ …调用可能是一个选项。

这些解决scheme没有考虑到库函数可能以不可控制的方式自行打开和closures文件,例如,在/ proc文件系统中打开std :: thread :: hardware_concurrency()的某些实现。

文件stream如[file.streams] C ++标准部分不是一个选项。

是否有一个简单而可靠的机制,在multithreading的情况下closures文件?


编辑:

常规文件:虽然大多数情况下没有不可用的打开文件描述符累积,但有两种情况可能会触发问题:1.某些恶意软件以高频率发出信号2.networking文件系统在高速caching刷新之前失去连接。

套接字:根据Stevens / Fenner / Rudoff的说法,如果套接字选项SO_LINGER在涉及连接套接字的文件描述符上设置,并且在close()过程中,定时器在FIN-ACKclosures序列完成之前消失,则close()失败作为普通程序的一部分。 Linux不显示这种行为,但是,FreeBSD也是这样做的,并且还将errno设置为EAGAIN。 据我了解,在这种情况下,没有指定文件描述符是否失效。 C ++代码来testing行为: http : //www.sagnix.eu/misc/close.txt在那里testing代码输出看起来像在FreeBSD的竞争条件,如果不是,为什么不呢?

在closures()的调用中,可以考虑使用bocking信号。

这个问题已经在下一期的POSIX中解决了。 不幸的是,它已经变成了最近的TC2。 请参阅Austin Group Issue#529 的最终接受文本 。

这个问题没有实际的解决方案,因为POSIX根本没有解决这个问题。

不重试关闭可能会导致无法使用的打开文件描述符堆积。

尽管听起来像是正当的关注,但我从来没有见过这种情况,因为close()调用失败。

干净的解决方案可能涉及对新近关闭的文件描述符调用fstat()以及一个相当复杂的锁定机制。

不是真的。 当close()失败时,文件描述符的状态是未指定的 。 所以,你不能可靠地使用它的fstat()调用。 因为文件描述符可能已经关闭了。 在这种情况下,您将无效的文件描述符传递给fstat() 。 或者另一个线程可能重用了它。 在这种情况下,您将错误的文件描述符传递给fstat() 。 或者文件描述符可能已经由失败的close()调用破坏了。

当进程退出时,所有打开的描述符将被刷新并关闭。 所以,这不是一个实际的问题。 有人可能会争辩说,这将是一个长期运行的过程中, close()失败太频繁的问题。 但是我已经看到了这种情况,POSIX也没有提供任何替代方案。

基本上,除了报告问题发生之外,你不能做太多的事情。

为了缓解任何问题,请显式同步文件:

  1. (如果你正在使用FILE* ,首先调用fflush()来确保用户空间缓冲区被清空到内核。)
  2. 在文件描述符上调用fsync() ,将有关文件的内核数据和元数据清空到磁盘。

这些你可以重试错误,不用担心。 之后,可能在某些操作系统上中断关闭的文件描述符或句柄可能是一个小问题,特别是如果您检查对您很重要的操作系统(我怀疑在大多数相关的操作系统中没有问题)的行为。

而且,一旦文件和数据被刷新,在关闭期间被中断的机会要小得多,因为关闭实际上不应该接触到磁盘。 如果你确实得到了EIO或EINTR,只要(可选)记录并忽略它,因为做任何事情可能会造成更多的伤害,而不是好的。 这不是一个完美的世界。