【发布时间】:2014-05-01 10:23:55
【问题描述】:
经过多年的经验,我对 Posix 感到很平静。
然后我读到了大约 2002 年来自 Linus Torvalds 的 this 消息:
int ret; do { ret = close(fd); } while(ret == -1 && errno != EBADF);没有。
以上是
(a) 不便携
(b) 不是现行做法
“不可移植”部分来自以下事实(正如有人指出的那样 out),内核确实关闭 FD 的线程环境 如果出现错误,FD 可能已被(内核)有效地重用于 其他一些线程,第二次关闭FD是一个BUG。
不仅循环直到EBADF 不可移植,而且任何循环都是由于竞争条件,如果我没有将这些事情视为理所当然,我可能会注意到这种情况。
但是,在 GCC C++ 标准库实现中,basic_file_stdio.cc,我们有
do
__err = fclose(_M_cfile);
while (__err && errno == EINTR);
这个库的主要目标是 Linux,但它似乎没有注意到 Linus。
据我了解,EINTR 仅发生在系统调用 blocks 之后,这意味着内核在开始任何被中断的工作之前收到了释放描述符的请求。所以没有必要循环。确实,SA_RESTART 信号行为不适用于close,并默认生成这样的循环,正是因为它不安全。
那么这是一个标准库错误,对吧?在 C++ 应用程序关闭的每个文件上。
编辑:为了避免在某些专家给出答案之前引起过多的恐慌,我应该注意close 似乎只在特定情况下被允许阻止,也许从来没有适用于常规文件。我不清楚所有细节,但如果不通过fcntl 或setsockopt 选择加入某些东西,您不应该从close 看到EINTR。然而,这种可能性使通用库代码更加危险。
【问题讨论】:
-
另见 stackoverflow.com/q/13356497/153285 我在哪里获得了链接。
-
我认为 EINTR 将来自隐式 fflush,在这种情况下不会调用
close。为谨慎起见,应该明确调用 fflush。但是,鉴于您的链接,也许您的意思是close而不是fclose? -
@JimBalter 啊,好点子。而
fclose并没有在内部处理这个问题,因为它假装是一个系统调用。我认为这可能就是答案……但我们仍然需要验证这个循环不能导致两个文件被关闭。 -
@JimBalter 是的,我的问题是关于
close,而不是 stdio 或 iostreams,它们只是一个规范的用例和一个可靠的工作示例。 -
@JimBalter 所以。似乎没有办法可靠地关闭一个文件,而不是零或两个,在包括 Linux 在内的任何平台上使用 C 或 C++ 标准库,或使用 Posix
close而不深入研究特定于平台的文档。这有点糟糕。
标签: c linux multithreading signals posix