2011-12-19 2 views
4

Может ли кто-нибудь сказать мне, что не так с этим кодом?Ошибка перенаправления трубы Fork-exec

Таким образом, он создает входные и выходные каналы, а fork-exec - программу sort. Родитель читает словарь /usr/share/dict/words и записывает его в трубку, которая соответствует стандарту dup2() 'd до sort, а также считывает с нее вывод, печатая его на терминале (стандартный вывод родителя). Или, по крайней мере, это то, что должно было произойти.

Обратный путь говорит, что родительский висит на read() на линии 130 (помечен комментарием «XXX»). Это почти как если бы sort не знал о конце файла, но закрытие конца записи pipeIn должно «сигнализировать» об этом, верно?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <unistd.h> 

int main(int argc, char** argv) 
{ 
    int pipeIn[2]; 
    int pipeOut[2]; 

    if ((pipe(pipeIn)) == -1) 
    { 
     perror("pipe"); 
     exit(EXIT_FAILURE); 
    } 

    if ((pipe(pipeOut)) == -1) 
    { 
     perror("pipe"); 
     exit(EXIT_FAILURE); 
    } 

    pid_t child = fork(); 

    if (child == 0) 
    { 
     // This is child! 

     if ((dup2(pipeIn[0], STDIN_FILENO)) == -1) 
     { 
      perror("dup2"); 
      exit(EXIT_FAILURE); 
     } 

     if ((dup2(pipeOut[1], STDOUT_FILENO)) == -1) 
     { 
      perror("dup2"); 
      exit(EXIT_FAILURE); 
     } 

     if ((dup2(pipeOut[1], STDERR_FILENO)) == -1) 
     { 
      perror("dup2"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(pipeIn[0])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(pipeOut[1])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     if ((execlp("sort", "-r", NULL)) == -1) 
     { 
      perror("execlp"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    else if (child == -1) 
    { 
     perror("fork"); 
     exit(EXIT_FAILURE); 
    } 
    else 
    { 
     // This is parent! 

     if ((close(pipeIn[0])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(pipeOut[1])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     int dict = open("/usr/share/dict/words", O_RDONLY); 

     if (dict == -1) 
     { 
      perror("open"); 
      exit(EXIT_FAILURE); 
     } 

     char buf[1024]; 
     int count; 

     while ((count = read(dict, buf, sizeof(char) * 1024)) > 0) 
     { 
      putchar('.'); 

      if ((write(pipeIn[1], buf, count)) == -1) 
      { 
       perror("write 1"); 
       exit(EXIT_FAILURE); 
      } 
     } 

     if (count == -1) 
     { 
      perror("read"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(dict)) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(pipeIn[1])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 

     while ((count = read(pipeOut[0], buf, sizeof(char) * 1024)) > 0) // XXX 
     { 
      putchar('!'); 

      if ((write(STDOUT_FILENO, buf, count)) == -1) 
      { 
       perror("write 2"); 
       exit(EXIT_FAILURE); 
      } 
     } 

     if (count == -1) 
     { 
      perror("read"); 
      exit(EXIT_FAILURE); 
     } 

     if ((close(pipeOut[0])) == -1) 
     { 
      perror("close"); 
      exit(EXIT_FAILURE); 
     } 
    } 

    return EXIT_SUCCESS; 
} 

Благодарим за любой вклад (помилование каламбур).

+0

возможный дубликат [Возникли проблемы с вилкой(), труба(), dup2() и Exec() в C] (HTTP: // StackOverflow. com/questions/916900/having-trouble-with-fork-pipe-dup2-and-exec-in-c) – wallyk

+0

Я уже читал это, и это кажется совсем другим. – Doddy

+0

Я согласен - вопрос с перекрестными ссылками несколько отличается. –

ответ

2

Ваша проблема заключается в том, что вы не закрываете неиспользуемые концы трубы в процессе чили. Таким образом, вам необходимо добавить следующий код где-нибудь перед exec

if ((close(pipeIn[1])) == -1) 
    { 
     perror("close"); 
     exit(EXIT_FAILURE); 
    } 

    if ((close(pipeOut[0])) == -1) 
    { 
     perror("close"); 
     exit(EXIT_FAILURE); 
    } 
+0

+1 - Ты прав. Это противоречит интуиции, но если вы используете трубку в качестве стандартного ввода или стандартного вывода в дочернем процессе, тогда вы обычно заканчиваете ** оба ** дескриптора файла, возвращаемого 'pipe()'. –

+0

Да, сначала я этого не понимал, но теперь имеет смысл теперь, когда я думал об этом (чего у меня нет до сегодняшнего дня). После вилки есть два открытых дескриптора файла, которые могут записываться в канал. Таким образом, вы не можете получить 'eof' при чтении из трубы до тех пор, пока ВСЕ дескрипторы файлов для конца записи не будут закрыты. – Sodved

+0

Спасибо, он работает, но он не печатает список слов в обратном порядке. Является синтаксисом 'execlp (" sort "," -r ", NULL),' wrong? – Doddy

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