【问题标题】:dup() and cache flushdup() 和缓存刷新
【发布时间】:2014-11-03 13:20:36
【问题描述】:

我是C初学者,尝试使用dup(),我写了一个程序来测试这个功能,结果和我预期的有点不同。

代码

// unistd.h, dup() test

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);
    FILE *f_dup = fdopen(fd_dup, "w+");

    // write to file, use the duplicated file descriptor,
    fputs("hello\n", f_dup);
    fflush(f_dup);
    // close duplicated file descriptor,
    fclose(f_dup);
    close(fd_dup);

    // allocate memory
    int maxSize = 1024; // 1 kb
    char *buf = malloc(maxSize);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, maxSize, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}

程序尝试通过复制的fd写入,然后关闭复制的fd,然后尝试通过原始fd读取。

本以为当我关闭复制的fd时,io缓存会自动刷新,但事实并非如此,如果我去掉代码中的fflush()函数,原来的fd将无法读取写入的内容由已经关闭的重复fd。

我的问题是

这是否意味着当关闭重复的 fd 时,它不会自动刷新?


@编辑:

对不起,我的错误,我找到了原因,在我最初的程序中有:

close(fd_dup);

但没有:

fclose(f_dup);

使用fclose(f_dup); 替换close(f_dup); 后,它可以工作了。

所以,如果以正确的方式关闭,重复的 fd 会自动刷新,write()close() 是一对,fwrite()fclose() 是一对,不应该混合它们。

实际上,在代码中我可以直接将复制的 fd_dup 与write()close() 一起使用,根本不需要创建新的FILE

所以,代码可以是:

// unistd.h, dup() test

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define BUF_SIZE 1024 // 1 kb

extern void dup_test();

int main() {
    dup_test();
}

// dup()test
void dup_test() {
    // open a file
    FILE *f = fopen("/tmp/a.txt", "w+");
    int fd = fileno(f);
    printf("original file descriptor:\t%d\n",fd);

    // duplicate file descriptor of an opened file,
    int fd_dup = dup(fd);
    printf("duplicated file descriptor:\t%d\n",fd_dup);

    // write to file, use the duplicated file descriptor,
    write(fd_dup, "hello\n", BUF_SIZE);
    // close duplicated file descriptor,
    close(fd_dup);

    // allocate memory
    char *buf = malloc(BUF_SIZE);

    // move to beginning of file,
    rewind(f);
    // read from file, use the original file descriptor,
    fgets(buf, BUF_SIZE, f);
    printf("%s", buf);

    // close original file descriptor,
    fclose(f);

    // free memory
    free(buf);
}

【问题讨论】:

  • 你可能想strace你的程序来检查它实际上做了什么系统调用。在我的系统上,你的程序总是打印hello。我认为可能发生的事情是f_dup 被刷新,但f 在此之前查看您的文件(fopen)。
  • 既然你有fdopen你的fd,那么你应该主要操作的对象是FILE*。它们本质上是相同的东西,不要两次关闭相同的东西。而且,您对FILE*int 有点困惑,这意味着fdFILE * 是文件流,它是标准表示,因此它是跨平台的。 fd其实就是int,一个文件描述符表的索引号,是*nix系统的特性。
  • @zch 谢谢,strace 是一个很棒的工具!

标签: c flush dup


【解决方案1】:

来自dup 手册页:

从这些系统调用之一成功返回后,新旧文件描述符可以互换使用。它们引用相同的打开文件描述(参见 open(2)),因此共享文件偏移量和文件状态标志;例如,如果在其中一个描述符上使用 lseek(2) 修改了文件偏移量,则另一个描述符的偏移量也会改变。

这意味着当您写入重复的文件描述符时会更改查找指针,因此,在写入重复后从第一个文件描述符读取不应读取任何数据。

您正在使用 fdopen 创建重复流的分离 seek_ptr 和 end_ptr,这样,fd_dup 就不再是重复了。这就是为什么您可以在刷新和关闭流之后读取数据。

如果不刷新第二个文件描述符,我找不到任何关于为什么无法读取的有力事实。我可以补充一点,它可能与sync 系统调用有关。

毕竟,如果你需要一个 IO 缓冲区,你可能使用了错误的机制,检查命名管道和其他缓冲 OS 机制。

【讨论】:

  • 我在读之前写了rewind(),所以寻找指针不是问题。无论如何,感谢您的建议,代码只是尝试找出 dup() 的功能,在现实世界中的程序可能会使用不同的方法。
【解决方案2】:

我无法真正理解您的问题。我在 Microsoft VC2008(必须将 unistd.h 替换为 io.h)和 gcc 4.2.1 下对其进行了测试。

我注释掉了fflush(f_dup),因为它在关闭之前没有用,close(fd_dup); 因为文件描述符已经关闭,所以这段代码现在看起来像:

// write to file, use the duplicated file descriptor,
fputs("hello\n", f_dup);
// fflush(f_dup);
// close duplicated file descriptor,
fclose(f_dup);
// close(fd_dup);

而且它工作正常。我在两个系统上都上:

original file descriptor:       3
duplicated file descriptor:     4
hello

【讨论】:

  • 谢谢,我的错误,更新问题中描述的原因。
猜你喜欢
  • 2012-07-02
  • 2012-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
  • 1970-01-01
相关资源
最近更新 更多