【问题标题】:How can I check to see if a file descriptor was closed?如何检查文件描述符是否已关闭?
【发布时间】:2013-11-08 17:39:52
【问题描述】:

在 POSIX 环境中,当使用系统调用来操作文本文件 (open(), close(), read(), write()) 时,有没有办法检查我在使用 close(file_descriptor) 时是否真的关闭了文件描述符?

示例

int main(int argc, char **argv)
{
    int input_file; // file descriptor for input file
    int output_file; // file descriptor for output file
    input_file = open(argv[1], O_RDONLY));
    ouput_file = open(argv[2], ...file properties & permissions and crap.....);

    // blah blah blah...

    close(input_file);
    close(output_file);

    // what can I code here to check if the file descriptor was actually closed?
}

【问题讨论】:

    标签: c low-level low-level-code low-level-io


    【解决方案1】:

    最简单的方法可能是检查您的第一个 close 的返回值。

    if (close(input_file)) {
        perror("close");
    } else {
        // all good
    }
    

    这是唯一线程安全的方式。在多线程程序中,另一个线程可以获得一个新的文件描述符,该文件描述符回收刚刚关闭的文件描述符的 fd 编号。


    仅在单线程代码中,在关闭和检查之间没有任何东西可以回收 fd

    如果您想在之后检查文件描述符是否有效,那么您可以使用任何使用文件描述符的函数并检查它的错误代码。最不干预最轻量级的大概是fcntl/F_GETFL

    if (fcntl(fd, F_GETFL) < 0 && errno == EBADF) {
        // file descriptor is invalid or closed
    }
    

    您也可以再次调用close,它也可能失败并调用EBADF

    if (close(fd) && errno == EBADF) {
        // file descriptor is invalid or closed
    } else {
        // we successfully closed fd *now* (e.g. first close failed with EINTR)
        // or there was a different error
    }
    

    close 在成功时不会修改errno,但我们只在close 返回非零时读取errno,这意味着它已被设置。

    【讨论】:

    • @SteveJobs:这些方法中的每一个在多线程环境中都是危险的,因为有问题的文件描述符很可能已经被另一个线程回收,因为它上次被关闭了。
    • 邪恶的任务。应该是errno == EBADF
    • @Isaac 谢谢。好地方。已更正。
    • 在多线程程序中要小心。文件描述符被重用。因此,关闭一个 FD 可能会导致在 close() 之后立即打开另一个具有相同值的 FD - 如果另一个线程进入并很快打开另一个文件。执行此操作的唯一线程安全方法是检查返回值。
    • 这个答案不能保证有效。如果close() 成功,则不会修改errnoerrno 需要在调用close() 之前设置为0。之后检查文件描述符是否有效也不适用于多线程程序,或者在文件描述符可以重用的任何其他情况下。
    【解决方案2】:

    您可以查看close()的返回值和相应的错误号。

    来自http://pubs.opengroup.org/onlinepubs/009695399/functions/close.html

    成功完成后,返回0;否则,-1 应 被返回并设置 errno 以指示错误。

    [...]

    如果出现以下情况,close() 函数将失败:

    [EBADF]

    fildes 参数不是有效的文件描述符。

    【讨论】:

      【解决方案3】:

      检查文件描述符是否无效的唯一保存方法是在定义和每次成功关闭时将其显式设置为(例如)-1

      可以使用宏来完成:

      #define FD_INVALID (-1)
      
      #define FD_CLOSE_AND_INVALIDATE(fd) \
      do { \
        if (-1 == close(fd)) \
        { \
          perror("close failed"); \
        } \
        else \
        { \
          (fd) = FD_INVALID; \
        } \
      } while (0)
      
      int main(int argc, char ** argv)
      {
        int input_file = FD_INVALID; /* Properly initialise file descriptor for input file */
        int output_file = FD_INVALID; /*  Properly initialise file descriptor for output file */
      
        input_file = open(argv[1], O_RDONLY));
        ouput_file = open(argv[2], ...);
      
        /* Do something. */
      
        FD_CLOSE_AND_INVALIDATE(input_file);
        FD_CLOSE_AND_INVALIDATE(output_file);
      
        /* To check if the file descriptor was actually closed just test for FD_INVALID. */
      }
      

      【讨论】:

      • 如果系统有很多文件描述符,维护一个文件描述符的哈希映射,每次关闭时,将它们设置为-1。
      猜你喜欢
      • 1970-01-01
      • 2017-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-10
      • 2010-09-21
      • 2010-10-27
      • 1970-01-01
      相关资源
      最近更新 更多