Dup () and cache-flush

I am starting in C, trying to use dup()

, I wrote a program to test this function, the result is slightly different from what I expected.

Code

// 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);
}

      

The program will try to write through the duplicated fd, then close the duplicated fd, then try to read through the original fd.

I expected that when I close the duplicated fd the io cache will be automatically cleared, but this is not the case, if I remove the function fflush()

in the code, the original fd will not be able to read the content written by the duplicated fd that is already closed.

My question is :

Does this mean that when the duplicated fd is closed, it won't automatically reset?


@Edit:

Sorry my mistake, I found the reason, in my original program:

close(fd_dup);

      

but don't have:

fclose(f_dup);

      

after use fclose(f_dup);

for replacement, close(f_dup);

it works.

So, the duplicate fd will automatically hide if you close it appropriately, write()

and close()

is a pair, fwrite()

and fclose()

is a pair, should not mix them.

Actually, in code I could use the duplicated fd_dup directly with write()

and close()

, and there is no need to create a new one at all FILE

.

So, the code could be as simple as:

// 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);
}

      

+3


source to share


2 answers


I cannot understand your problem. I tested it under Microsoft VC2008 (it had to replace unistd.h with io.h) and gcc 4.2.1.

I commented fflush(f_dup)

because it is useless before closing and close(fd_dup);

because the file descriptor is already closed, so the code snippet now looks like this:

// 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);

      



And it works right. I get both systems:

original file descriptor:       3
duplicated file descriptor:     4
hello

      

+1


source


From the dup

man pages:

After a successful return from one of these system calls, the old and new file descriptors can be used interchangeably. They refer to the same open file description (see Open (2)) and thus share the file offset and file status flags; for example, if the file offset is changed with lseek (2) on one of the descriptors, the offset is also changed for the other.

This means that the lookup pointer changes when the duplicate file descriptor is written, so reading from the first file descriptor after writing the duplicate should not read any data.



You are using a fdopen

duplicate stream to create separate seek_ptr and end_ptr, so it fd_dup

stops being duplicate. This is why you can read the data after flushing and closing the stream.

I couldn't find any strong facts about why you can't read unless you clear the second file descriptor. I may add that it might be system call related sync

.

After all, if you need an I / O buffer, you might be using the wrong mechanism, check named pipes and another buffering mechanism.

+2


source







All Articles