2014-11-03 3 views
3

Я начинаю с нуля, пытаясь использовать dup(), я написал программу для проверки этой функции, результат немного отличается от того, что я ожидал.dup() и cache flush

Код:

// 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, кеш-ке будет автоматически очищен, но это не так, если я удалю функцию fflush() в коде, исходный fd не сможет прочитать содержимое, написанное дублированный fd, который уже закрыт.

Мой вопрос:

ли это означает, что, когда близко дублируется FD, он не будет делать вровень автоматически?


@Edit:

Я извиняюсь, моя ошибка, я нашел причину, в моей первоначальной программе есть:

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); 
} 
+2

Возможно, вы захотите «отцепить» свою программу, чтобы проверить, какие именно системные вызовы она на самом деле делает. В моей системе ваша программа всегда печатает «привет». Я думаю, что может произойти, что 'f_dup' очищается, но' f' делает вид вашего файла до этого (на 'fopen'). – zch

+0

, так как у вас есть 'fdopen' ваш' fd', объект, в котором вы должны работать, это 'FILE *'. они по сути то же самое, не закрывайте одно и то же дважды. и вы немного сбиты с толку о 'FILE *' и 'int', который должен быть' fd'. 'FILE *' является файловым потоком, это стандартное представление, поэтому оно является кросс-платформенным. 'fd' - фактически' int', индексный номер таблицы дескриптора файла, это функция * nix-системы. – HuStmpHrrr

+0

@zch Thx, strace - отличный инструмент! –

ответ

1

Я не могу понять вашу проблему. Я тестировал его под 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 
+0

Спасибо, моя ошибка, причина, описанная в обновленном вопросе. –

2

От dup людей страницы:

После успешного возвращения из одной из этих системных вызовов, старых и новых файловых дескрипторов, может быть, используется взаимозаменяемо. Они ссылаются на одно и то же описание открытого файла (см. Open (2)) и, таким образом, разделяют флаги смещения файлов и состояния файла; например, если смещение файла изменяется с помощью lseek (2) в одном из дескрипторов, смещение также изменяется для другого.

Это означает, что указатель поиска изменяется при записи в дублированный дескриптор файла, поэтому чтение из первого дескриптора файла после записи в дубликат не должно считывать данные.

Вы используете fdopen для создания разделенных seek_ptr и end_ptr дублированного потока, таким образом, fd_dup перестает быть дублированием. Вот почему вы можете читать данные после промывки и закрытия потока.

Я не мог найти убедительных фактов о том, почему вы не можете прочитать, если вы не очистите второй файловый дескриптор. Я могу добавить, что это может быть связано с системным вызовом sync.

В конце концов, если вам нужен буфер ввода-вывода, возможно, вы используете неправильный механизм, проверьте именованные каналы и другой механизм буферизации.

+0

Я сделал перемотку() после записи перед чтением, поэтому указатель поиска не является проблемой. Во всяком случае, спасибо за ваше предложение, код просто попытается выяснить функцию dup(), в реальной программе может использоваться другой подход. –

Смежные вопросы