Ввод-вывод в стандарте C и C POSIX

У меня возникла проблема при тестировании разностной функции ввода-вывода между стандартом C и C POSIX.

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

Первая программа будет написана с использованием стандартных функций POSIX (открыть, прочитать).

int main(int argc, char **argv){
    int fd; /* Descriptor */
    char *fic = argv[1]; /* Le nom du fichier */
    int end = 0; 

    /* Sémaphore */
    struct sembuf operation; 
    int sem_id;    
    sem_id = semget(ftok(fic, 'S'), 1, 0666|IPC_CREAT); 
    semctl(sem_id, 0, SETVAL, 1); 

    if((fd = open(fic, O_RDONLY, 0666))==-1){
        perror("open file\n"); 
        }

    int i = 0; 
    char c; 
    for(i=0; i<3; i++){
        if(fork()==0){
            /* Lire */ 
            while(end==0){
                operation.sem_num = 0; 
                operation.sem_op = -1; 
                semop(sem_id, &operation, 1);

                if(read(fd, &c, sizeof(char))>0){
                    printf("[Pid=%d]%c\n", getpid(), c);
                    }
                else{
                    end = 1; 
                    break; 
                    }

                operation.sem_num = 0; 
                operation.sem_op = 1; 
                semop(sem_id, &operation, 1);
                sleep(1); 
                } 
            return EXIT_SUCCESS; 
            }
        else continue; 
        }

    for(i=0; i<3; i++){
        wait(NULL); 
        }

    close(fd); 
    semctl(sem_id, 0, IPC_RMID, NULL); 
    return EXIT_SUCCESS;     
    }

Вторая программа будет написана с использованием библиотечных функций C (fopen, fgetc).

int main(int argc, char **argv){
    FILE *fd; /* Descriptor */
    char *fic = argv[1];
    int end = 0; 

    /* Sémaphore */
    struct sembuf operation; 
    int sem_id;    
    sem_id = semget(ftok(fic, 'S'), 1, 0666|IPC_CREAT); 
    semctl(sem_id, 0, SETVAL, 1); 

    if((fd = fopen(fic, "r"))==NULL){
        perror("open file\n"); 
        }

    int i = 0; 
    char c; 
    for(i=0; i<3; i++){
        if(fork()==0){
            while(end==0){
                operation.sem_num = 0; 
                operation.sem_op = -1; 
                semop(sem_id, &operation, 1);

                if((c = fgetc(fd))!=EOF){
                    printf("[Pid=%d]%c\n", getpid(), c);
                    }
                else{
                    end = 1; 
                    break; 
                    }

                operation.sem_num = 0; 
                operation.sem_op = 1; 
                semop(sem_id, &operation, 1);
                sleep(1); 
                } 
            return EXIT_SUCCESS; 
            }
        else continue; 
        }

    for(i=0; i<3; i++){
        wait(NULL); 
        }

    fclose(fd); 
    semctl(sem_id, 0, IPC_RMID, NULL); 
    return EXIT_SUCCESS;     
    }

В случае C POSIX я обнаружил, что 3 процесса работают параллельно, используя механизм блокировки семафора. Но в случае стандарта C есть только один процесс, который читает и отображает символы на экране.

Может ли кто-нибудь сказать мне причину этой разницы?

Огромное спасибо.


person minh-hieu.pham    schedule 09.11.2014    source источник
comment
Обратите внимание, что указатели файлов и стандартные потоки ввода-вывода являются также частью POSIX.   -  person pilcrow    schedule 20.12.2014


Ответы (1)


Если я правильно понимаю, вы запускаете свои программы и видите такой вывод:

$ echo foo > /tmp/input
$ ./synchronized-read /tmp/input   # PIDs differ; the readers "share" the input
[Pid=124] f
[Pid=123] o 
[Pid=125] o
[Pid=123]                          # <-- (newline)

$ ./synchronized-fgetc /tmp/input  # PIDs are all the same; one reader reads all
[Pid=567] f
[Pid=567] o
[Pid=567] o
[Pid=567]                          # <-- (newline)

Причина в том, что read работает непосредственно с файлами, тогда как fgetc работает с буферизованными стандартными потоками ввода-вывода.

Итак, в первой программе каждый считыватель считывает по байту из файла напрямую. Во второй программе первый читатель, получивший семафор, читает весь файл — вы не показали нам образец ввода, но это соответствует описанию вашей проблемы — это означает, что другие читатели немедленно сталкиваются с EOF и завершают работу.

Если вы измените дочернюю логику в каждом на printf("[Pid=%d]EOF\n", getpid()) в конце ввода, вы ясно увидите это.

person pilcrow    schedule 20.12.2014