цепь труб между процессами - PullRequest
0 голосов
/ 11 января 2012

Я хочу иметь одного родителя с двумя дочерними элементами.

Родитель читает из файла "a.txt" и отправляет через канал первому дочернему элементу;первый ребенок читает символы и отправляет второму ребенку символы нижней буквы.

Второй дочерний элемент печатает в «b.txt» каждый отдельный символ и количество появлений (на строку), а затем отправляет через канал родительскому элементу количество различных символов.Родитель печатает результат от второго потомка.

Я проделал конвейер от родителя до 1 потомка и, чтобы проверить, вернул ли я трубку родителю.Что я не могу понять, так это как заставить трубу идти ко второму ребенку.Я искал информацию о dup2, но я не понимаю, как заставить это работать.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>

void main()
{

    int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
    char *c = (char *)malloc(sizeof(char));

    if (pipe(pfd1) < 0) {
        printf("Eroare la crearea pipe-ului\n");
        exit(1);
    }
    if (pipe(pfd2) < 0) {
        printf("Eroare la crearea pipe-ului\n");
        exit(1);
    }
    if ((pid1 = fork()) < 0) {
        printf("Eroare la fork\n");
        exit(1);
    }

    if (pid1 == 0) {    /*child */
        close(pfd1[1]);
        while (read(pfd1[0], c, 1) > 0) {
            //printf("%s",c);
            if (islower(*c)) {
                close(pfd2[0]);
                //inchid capul de citire; scriu in pipe
                write(pfd2[1], c, 1);
                ////dup??????
            }
        }
        printf("\n");
        write(pfd[1], buff, len);

        close(pfd1[0]);
        close(pfd2[1]);
        exit(0);
    }

    if ((pid2 = fork()) < 0) {
        printf("Eroare la fork\n");
        exit(1);
    }

    if (pid2 == 0) {
        printf("second child");
        exit(0);
    }

    /* parent */
    close(pfd1[0]);
    close(pfd2[1]);
    fd = open("date.txt", O_RDONLY);
    while (read(fd, c, 1) > 0) {
        write(pfd1[1], c, 1);
    }
    close(pfd1[1]);     /* la sfarsit inchide si capatul utilizat */
    close(pfin);

    while (read(pfd2[0], c, 1) > 0)
        printf("%s", c);
    close(pfd2[0]);
    printf("%d", wait(&status));
    printf("%d", wait(&status));

}

Ответы [ 3 ]

2 голосов
/ 11 января 2012

У меня есть несколько конкретных комментариев к вашему коду:

char *c = (char *)malloc(sizeof(char));

Хотя в этом нет ничего плохого, также нет необходимости выделять это char из кучи. Более идиоматический подход будет использовать char c; здесь и затем передавать &c на read(2) и write(2) системные вызовы. (Еще более идиоматично было бы использовать стандартное средство ввода-вывода C; freopen(3), getchar(3) и putchar(3) - но не делайте этот переход, пока у вас не работает этот код точно так, как вы хотите, потому что он дополнительное осложнение проблемы, которую вы пытаетесь решить.)

if ((pid1 = fork()) < 0) {
    printf("Eroare la fork\n");
    exit(1);
}

Используя собственное сообщение об ошибке, вы упускаете важную информацию об ошибке. Вы должны использовать perror(3), чтобы напечатать сообщение об ошибке. Это даст вам и вашим пользователям фактическую причину ошибок, которые они могут искать. fork(2) может произойти сбой, если ваш пользователь запускает максимальный предел процесса setrlimit(2) NPROC, общесистемный предел процесса, из памяти ядра.

if ((pid1 = fork()) < 0) {
   perror("Eroare la fork");
   exit(1);
}

Вам также следует проверить возвращаемое значение из open(2) вызовов. (Вы должны также проверить возвращаемые значения из write(2) и close(2) на наличие ошибок, но обработка этих ошибок сложнее. Просто распечатка ошибки и выход из нее - хороший старт для большинства программ.)

    while (read(pfd1[0], c, 1) > 0) {
        //printf("%s",c);
        if (islower(*c)) {
            close(pfd2[0]);

Это неправильное расположение для вызова close(2) - вам не следует закрывать этот файловый дескриптор снова и снова для каждого входного символа. Если бы вы проверяли возвращаемое значение close(2), вы бы заметили, что errno установлено на EBADF, поскольку дескриптор файла больше не действует при втором и последующих вызовах.

Теперь перейдем к проблеме, для которой вы пришли: последовательность вызовов fork(), pipe() и dup2(), которые подключат все ваши процессы в конвейере и отправят данные обратно в родительский процесс. Так как pipe(2) создает однонаправленные pipe(7) s, вам нужно позвонить pipe(2) четыре раза - для обоих направлений между родителем и детьми. Если вы храните конечные точки канала в массивах с именами, которые что-то для вас значат, их будет легче отслеживать. Возможно, создайте массивы с именем to_ для записи и from_ для чтения из:

int to_child[2];
int from_parent[2];
int to_parent[2];
int from_child[2];

for (int i=0; i<2; i++) {
    int p[2];

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

    /* from parent to child */

    to_child[i] = p[1];
    from_parent[i] = p[0];

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

    /* from child to parent */

    to_parent[i] = p[1];
    from_child[i] = p[0];
}

Обратите внимание, что на самом деле не требуется для использования dup2(2) для перестановки файловых дескрипторов, если вы не хотите выполнить других программ для обработки задачи "фильтра". Просто read(2) с использованием дескрипторов from_parent[...] или from_child[...] и write(2) для дескрипторов to_child[...] и to_parent[...].

Может быть, все было бы проще с socketpair(2) с использованием AF_UNIX для создания двунаправленных сокетов , которые затем можно читать и записывать таким же образом, как и любой другой стиль BSD разъем. См. socket(7) и unix(7) для обзора.

0 голосов
/ 12 января 2012

Спасибо за ваши ответы.Вот код всей проблемы.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>

void main()
{

 int pfd1[2],pfd2[2],pfd3[2],pid1,pid2,status,fd,fo;
 char letter[32][2];
 int letternumber=0,i,sw=0;
 char* c = (char*)malloc(sizeof(char));
 //pipe creation
 if(pipe(pfd1)<0){ 
    perror("Eroare la crearea pipe-ului"); 
    exit(1); 
 } 

 if(pipe(pfd2)<0){ 
    perror("Eroare la crearea pipe-ului\n"); 
    exit(1); 
 }

 if(pipe(pfd3)<0){ 
    perror("Eroare la crearea pipe-ului\n"); 
    exit(1); 
 }  
 //make first child
 if((pid1=fork())<0){ 
    perror("Eroare la fork\n"); 
    exit(1); 
 } 
 if(pid1==0) //child process
 { 
 if(close(pfd1[1])<0) {perror("Eroare close");exit(1);} // close write end; process will read from pipe
 if(close(pfd2[0])<0) {perror("Eroare close");exit(1);} //close read end; write in pipe
 while (read(pfd1[0], c, 1) > 0){
    if(islower(*c))  write(pfd2[1],c,1);//writing in pipe

 }
 if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} /* close other ends */ 
 if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
 exit(0); 
 } 


 //make second child
 if((pid2=fork())<0){ 
  perror("Eroare la fork"); 
  exit(1); 
 } 

 if(pid2==0){ /* second child*/ 
      if(close(pfd1[0])<0) {perror("Eroare close");exit(1);}
  if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
  if((fo=open("statistica.txt", O_CREAT | O_TRUNC | O_RDWR, 
                S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | 
                S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IROTH))==-1)
    {perror("Eroare open");exit(1);}
  if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
  letter[0][0]='A';
  letter[0][1]=0;
  while(read(pfd2[0],c,1)>0) {          
    for(i=0;i<=letternumber;i++) 
          if(letter[i][0]==*c) {letter[i][1]++;sw=1;}
    if (sw==0){
          letter[letternumber][0]=*c;
          letter[letternumber++][1]=1;
    }     
    sw=0;    
  }
  printf("\n");//why won't it write to file without it; 
                   //wihtout it, it writes to screen?
  if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
  dup2(fo,1);
  for(i=0;i<letternumber;i++) 
      printf("%c %d\n",letter[i][0],letter[i][1]);
  if(close(fo)<0) {perror("Eroare close");exit(1);}
  if(close(pfd3[0])<0) {perror("Eroare close");exit(1);} //close read end; going to write in pipe
  dup2(pfd3[1],1);
  printf("%d",letternumber);
  if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
  exit(0);
 }  

 /* parent process */ 
 if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} // close read end; write in pipe
 if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
 if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
 if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}

 if((fd=open("date.txt",O_RDONLY))==-1)
  {perror("Eroare open");exit(1);}

 while(read(fd,c,1)>0)
      write(pfd1[1],c,1); //write in pipe

 if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
 //dup2(pfd3[0],0);
 while(read(pfd3[0],c,1)>0) printf("%c",*c);
 printf("\n");
 if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
 wait(&status);
 wait(&status);
}
0 голосов
/ 12 января 2012

Вам не нужно dup().Просто откройте каналы в родительском и затем в каждом процессе close() конечные точки, которые вам не нужны, и просто используйте конечные точки, которые вам нужны.

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

...