【问题标题】:If fclose() fails, is the file descriptor still open?如果 fclose() 失败,文件描述符是否仍然打开?
【发布时间】:2021-05-08 21:49:14
【问题描述】:

想象以下代码作为线程运行:

void *thread_worker(void *q) {
 for (;;) {
  int fd = some_queue_get(q);
  FILE *writer = fdopen(fd, "w");
  if (!writer) { perror("fdopen"; close(fd); continue; }
  // do something with writer

  if (fclose(writer) == EOF) {
   perror("fclose writer");
   // should fd be closed here?
   close(fd);
  }
}

fclose(3) 可能会因各种原因而失败 - 是否可以保证底层文件描述符何时关闭或之后仍处于打开状态?

  • 如果 fd 在刷新失败时没有被 fclose 关闭,则会在没有额外关闭的情况下泄漏 fd。
  • 如果 fd 被 fclose 关闭,额外的关闭可能会关闭另一个线程新打开的文件描述符。

【问题讨论】:

  • 来自文档:如果 fclose 失败,对流的任何进一步访问(包括对 fclose 的另一个调用)都会导致未定义的行为。
  • @Jabberwocky 我不想访问流,但是文件描述符
  • 鉴于您的函数名称 - thread_worker,close(fd) 是危险的。如果fclose() 确实关闭了它的文件描述符但无论如何都失败了,那么另一个线程可以重用该值,并且您可以直接从另一个线程下将其关闭。
  • @AndrewHenle 正如 thejonny 在最后一句话中所写...
  • @Thomas 而且真的没有办法检查这种情况。

标签: c posix fclose


【解决方案1】:

man fclose 也没有在我的系统上提供答案,但man 3p fclose 揭示了official version from the POSIX Programmer's manual,这在这件事上要全面得多:

fclose() 函数应在与 stream 指向的流相关联的文件描述符上执行 close() 的等效操作。

【讨论】:

  • 但是close() can fail 除了记录它之外,您无能为力。特别是,您无法安全地重试close() 调用。
  • 这也匹配当前的 glibc 行为,但不是第一个 glibc 源,如果发现谷歌搜索(一个古老的版本):)
【解决方案2】:

答案是 NO,C 标准对此含糊不清(强调我的):

7.21.5.1 fclose 函数

概要

#include <stdio.h>
int fclose(FILE *stream);
 

说明
对fclose 函数的成功调用会导致stream 指向的流被刷新并关闭相关文件。流的任何未写入缓冲数据都将传递到主机环境以写入文件;任何未读缓冲数据都将被丢弃。 无论调用是否成功,流都会与文件解除关联,并且由setbuf 或setvbuf 函数设置的任何缓冲区都会与流解除关联(如果它是自动分配的,则会被解除分配)。

退货
如果流成功关闭,fclose 函数返回零,如果检测到任何错误,则返回 EOF。

【讨论】:

  • C 标准无关紧要,因为文件描述符不是标准的 C 概念。您需要查看一些 POSIX/Unix 规范/实现来了解fclose 对文件描述符的影响。
  • @Gilles'SO-stopbeingevil':通过丢弃FILE 结构同时保持关联的文件描述符打开来实现流与文件解除关联是不正当的.然而还有一个更普遍的问题:close() 可能会失败,原因是我从未见过有人处理过生产代码。如果被信号中断,close() 失败,errno 设置为EINTR 并且文件描述符仍然处于打开状态。
猜你喜欢
  • 2011-11-09
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
相关资源
最近更新 更多