2011-01-12 2 views
1

Я только начал работать с UNIX FIFO, и я кое-что обнаружил, экспериментируя с моей первой программой FIFO. Программа работает следующим образом: после создания FIFO запускаются два процесса с использованием функции fork(). Детский процесс читает то, что отец передает ему через FIFO, и печатает его на экране. Обмен данными - это строка, указанная в качестве аргумента. Вопрос: в разделе «Отец», если я забуду закрыть входную часть FIFO (это означает, что я исключаю строку close(fd)), программа просто зависает, даже если данные между процессами будут обмениваться правильно. В противном случае все работает нормально, и программа завершается с помощью подвески. Может кто-нибудь объяснить мне почему?UNIX FIFO: процесс зависает, если я не закрываю входную сторону fifo

Благодарим за ваше терпение. Вот код основной функции:

int main(int argc, char *argv[]) 
{ 
    if(argc != 2) 
    { 
     printf("An argument must be specified\n"); 
     return -1; 
    } 

    int ret = mkfifo("./fifo.txt", 0644); 
    char buf; 

    if(ret < 0) 
    { 
     perror("Error creating FIFO"); 
     return -1; 
    } 

    pid_t pid = fork(); 

    if(pid < 0) 
    { 
     perror("Error creating child process"); 
     return -1; 
    } 

    if(pid == 0) /* child */ 
    { 
     int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */ 

     while(read(fd, &buf, 1) > 0) 
     { 
      write(STDOUT_FILENO, &buf, 1); 
     } 
     write(STDOUT_FILENO, "\n", 1); 
     close(fd); 
     return 0; 
    } 
    else /* father */ 
    { 
     int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */ 

     write(fd, argv[1], strlen(argv[1])); 
     close(fd); 
     waitpid(pid, NULL, 0); 
     return 0; 
    } 
} 
+2

Не может быть, что детский процесс ухаживает, потому что он ждет, когда отец закроет ФИФО, но так как отец не делает этого, ребенок ждет навсегда, чтобы ФИФО был закрыт, а отец тоже ждет ребенок заканчивается? – matteoamc

ответ

5

read(2) блоки до тех пор, пока персонажи доступны или канал закрыт на другом конце. Процесс отца должен закрыть трубу, чтобы вернуть последнего ребенка read(). Если вы опустите close(fd) в отце, ребенок будет блокироваться в read(), пока отец не выйдет (закрытие трубы автоматически), но отец будет висеть в waitpid(), пока ребенок не выйдет.

+0

Конечно, вы правы, как я мог этого не узнать раньше! Функция read() не вернет 0, пока родительский процесс на другой стороне FIFO не закроет ее. Большое спасибо за Вашу помощь! – matteoamc

0

Прежде всего: есть несколько проблем с кодом, который вы опубликовали.

  1. Нет никаких директив #include, следовательно, нет прототипов в рамках любой из функций, которые вы вызываете. C89 требует прототипов для вариационных функций, таких как printf(); C99 требует прототипов для всех функций. Для обоих C89 и C99 требуются декларации в области O_RDONLY, O_WRONLY, STDOUT_FILENO и NULL.
  2. -1 не является допустимым возвратным значением для main().
  3. C89 не позволяет смешивать объявления и заявления.

Небольшая нить: обычная номенклатура «родитель и ребенок», а не «отец и ребенок».

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

#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/wait.h> 

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

int 
main(int argc, char *argv[]) 
{ 
    if (argc != 2) { 
     printf("An argument must be specified\n"); 
     return 1; 
    } 

    int ret = mkfifo("./fifo.txt", 0644); 
    char buf; 

    if (ret < 0) { 
     perror("Error creating FIFO"); 
     return 1; 
    } 

    pid_t pid = fork(); 

    if (pid < 0) { 
     perror("Error creating child process"); 
     return 1; 
    } 

    if (pid == 0) { /* child */ 
     int fd = open("./fifo.txt", O_RDONLY); /* opens the fifo in reading mode */ 

     while(read(fd, &buf, 1) > 0) { 
      write(STDOUT_FILENO, &buf, 1); 
     } 
     write(STDOUT_FILENO, "\n", 1); 
     close(fd); 
     return 0; 
    } else { /* parent */ 
     int fd = open("./fifo.txt", O_WRONLY); /* opens the fifo in writing mode */ 

     write(fd, argv[1], strlen(argv[1])); 
     close(fd); 
     waitpid(pid, NULL, 0); 
     return 0; 
    } 
} 

Но самое главное, вы не упомянули, что операционная система и компилятор вы используете.

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

+0

Кто сказал, что это C89 – JeremyP

+0

Бах, конечно, я неспособен воспроизвести вашу проблему - я скомпилировал и запустил программу, как указано, вместо удаления оператора 'close()', как вы указали. Что сказал Джеремип. – DES

+0

JeremyP, это либо C89, либо C99, либо некоторый диалект, полученный от одного или другого; в любом случае программа не будет компилироваться, как указано, даже при наиболее прощании компиляторов из-за отсутствия деклараций (или макроопределений) для 'O_RDONLY',' O_WRONLY', 'STDOUT_FILENO' и' NULL'. – DES

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