POSIX/UNIX:如何可靠地关闭文件描述符
POSIX/UNIX: How to reliably close a file descriptor
问题:
在使用EINTR或EIO的close((系统调用失败后,未指定文件是否已关闭。(http://pubs.opengroup.org/onlinepubs/9699919799/)在多线程应用中,重试关闭可能会关闭其他线程打开的不相关文件。不重试关闭可能会导致无法使用的打开文件描述符堆积。一个干净的解决方案可能涉及对新关闭的文件描述符调用fstat((和一个相当复杂的锁定机制。此外,正在序列化所有打开/关闭/接受/。。。使用单个互斥体的调用可能是一种选择。
这些解决方案没有考虑到库函数可能会以不可控的方式自行打开和关闭文件,例如,std::thread::hardware_concurrency((的某些实现会打开/proc文件系统中的文件。
[文件.流]C++标准部分中的文件流不是一个选项。
有没有一种简单可靠的机制可以在存在多个线程的情况下关闭文件?
编辑:
常规文件:虽然大多数情况下不会累积不可用的打开文件描述符,但有两种情况可能会引发问题:1.某些恶意软件以高频率发出的信号2.在刷新缓存之前丢失连接的网络文件系统。
套接字:根据Stevens/Fenner/Rudoff的说法,如果套接字选项SO_LINGER是在引用连接套接字的文件描述符上设置的,并且在close((过程中,计时器在FIN-ACK关闭序列完成之前过期,那么close(。Linux没有显示这种行为,但是FreeBSD显示了,并且还将errno设置为EAGAIN。据我所知,在这种情况下,未指定文件描述符是否无效。测试行为的C++代码:http://www.longhaulmail.de/misc/close.txt在我看来,那里的测试代码输出就像FreeBSD中的竞争条件,如果不是,为什么不呢?
可以考虑在调用close((期间阻塞信号。
此问题已在POSIX中为下一个问题修复;不幸的是,这是一个太大的变化,无法进入最近的TC2。参见Austin Group第529期的最终接受文本。
不重试关闭可能会导致无法使用的打开文件描述符堆积。
尽管这听起来是合理的担忧,但我从未见过由于close()
调用失败而发生这种情况。
一个干净的解决方案可能涉及在新关闭的文件描述符上调用
fstat()
和一个相当复杂的锁定机制。
不是。当close()
失败时,文件描述符的状态为未指定。因此,您不能可靠地将其用作fstat()
调用。因为文件描述符可能已经关闭。在这种情况下,您将向fstat()
传递一个无效的文件描述符。或者其他线程可能重用了它。在这种情况下,您将错误的文件描述符传递给fstat()
。或者文件描述符可能被失败的close()
调用损坏。
当进程退出时,所有打开的描述符都将被刷新并关闭。所以,这并不是一个实际的问题。有人可能会说,在close()
经常失败的长期运行过程中,这将是一个问题。但我在我的经验中看到了这种情况,POSIX也没有提供任何替代方案。
基本上,除了报告问题发生之外,你对此无能为力。
要缓解任何问题,请显式同步文件:
- (如果您在
FILE*
上操作,请首先在其上调用fflush()
,以确保用户空间缓冲区已清空到内核。( - 在文件描述符上调用
fsync()
,将有关该文件的任何内核数据和元数据刷新到磁盘
您可以在出现错误时重试,而无需额外担心。在那之后,在某些操作系统上,可能在中断关闭时泄露文件描述符或句柄可能是一个小问题,尤其是如果您检查对您来说很重要的操作系统的行为(我怀疑在大多数相关的操作系统中都没有问题(。
此外,一旦文件和数据被刷新,在关闭过程中被中断的可能性就会小得多,因为关闭时实际上不应该接触磁盘。如果你确实得到了EIO或EINTR,只需(可选(记录并忽略它,因为做其他事情可能弊大于利。这不是一个完美的世界。
- 使用VerQueryValue检索应用程序的文件描述
- 如何在C/C++中用FD_set Unix设置套接字文件描述符
- I2C 文件描述符上的 I2C 总线可写/可读标志
- 许多文件描述符在调用sys_clone时
- AMQP-CPP >处理程序中的错误文件描述符
- 如何使用 WINAPI 和 C++ 提取可执行文件的文件描述?
- 正在等待在非阻塞文件描述符上长时间运行ioctl
- 有没有适用于Windows.lib文件的GNU二进制文件描述符(BFD)
- 如何强制文件描述符缓冲我的输出
- 如何从 boost::asio::ssl::stream<boost::asio::ip::tcp::socket> 获取本机套接字文件描述器?
- 哪个更适合从C++写入敏感的日志文件,在文件描述符上写()或文件上的fprintf()?
- 将 select() 与非基于文件描述符的输入一起使用
- accept(..) 似乎正在修改我给它的文件描述符参数
- 使用 Select 多路复用未命名的管道和其他文件描述符
- 提升 ASIO 绑定:错误的文件描述符
- 使用文件描述符移动对象
- 无法从零MQ ZMQ_SERVER套接字中获取文件描述符
- read() 上的不同行为取决于写入不可写内存时表示文件、匿名管道或套接字的文件描述符
- 我可以在不使用 FIOCANCEL 的情况下关闭 VxWorks 中的文件描述符吗?
- 将 Boost Asio 与 ZeroMQ 集成,文件描述符错误?