Как родитель создает канал между каждым дочерним элементом и самим собой, и каждый ребенок отправляет количество слов родителю через канал - PullRequest
1 голос
/ 10 июля 2020

Написанный мной код определяет количество слов в нескольких текстовых файлах, создавая несколько процессов, каждый из которых отвечает за один файл и подсчитывает его слова.

Я хочу использовать каналы чтобы узнать общее количество слов во всех файлах.

Итак, родительский элемент должен:

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

  2. сообщает общее количество слов во всех файлах, добавляя числа, полученные по каналам

  3. проверяет статус выхода каждый дочерний элемент и распечатывает, как этот дочерний элемент вышел

также позволяет каждому дочернему элементу:

  1. отправляет количество слов родителю через канал
  2. отправить 0 как количество слов через конвейер родителю, если файл не существует или произошла какая-либо другая ошибка
  3. возвращает / завершает работу с 0, если он успешно открыл файл и подсчитал количество слов в этом фи le, возвращает / выходит с 1, если есть ошибка (например, файл не существует et c.)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

#define MAX_CHAR 100

pid_t getpid(void);
pid_t getppid(void);

char* itoa(int i, char b[]){
    char const digit[] = "0123456789";
    char* p = b;
    if(i<0){
        *p++ = '-';
        i *= -1;
    }
    int shifter = i;
    do{ //Move to where representation ends
        ++p;
        shifter = shifter/10;
    }while(shifter);
    *p = '\0';
    do{ //Move back, inserting digits as u go
        *--p = digit[i%10];
        i = i/10;
    }while(i);
    return b;
}
int countWords(char * fp, int pid) {
   FILE * file;
   int words = 0;
   char word[MAX_CHAR];
   //execute this function only if child process of parent, no gradchild is allowed to execute this function!
   if (pid == getppid()) {
      file = fopen(fp, "r");
      if (file == NULL) {
         return -1;
      }
      //find string in the file and count the words.
      while (fscanf(file, "%s", word) != EOF) {
         words++;
      }
      return words;
   } else {
      return -1;
   }
   return 0;
}

int main(int argc, char * arvg[]) {
   //if invalid arguments
   if (argc < 2) {
      fprintf(stderr, "ERROR: INVALID ARGUMENTS");
      exit(-1);
   }

   int count = 0, pid, ppid, status, totalwords;
   
   int result = -1;
   int fd[2];
   char string[100];
   char readbuffer[80];
   int *write_fd = &fd[1];
   int *read_fd = &fd[0];
   result = pipe(fd);
   if(-1 == result){
     perror("pipe");
     return -1;
   }
   //creates (argc - 1) child processes using fork()
   pid = (int) malloc((argc - 1) * sizeof(int));
   //parent pid
   ppid = getpid();

   //each child process to count the number of words in each file
   for (int i = 1; i < argc; i++) {
      //child process
      pid = fork();
      if( pid == -1){
          perror("failed to fork");
          return -1;
      }else if (pid == 0) {
         // call a function to count the number of words in file arvg[i]
         int words = countWords(arvg[i], ppid);
         close(*read_fd);
         if (words >= 0) {
            printf("Child process pid_%d for %s :number of words is %d\n", i, arvg[i], words);
            //I don't know how to write int into the pipe,so below might be wrong
            write(*write_fd, words, 1);
          
            return 0;
         } else if (words == -1) {
            printf("Child process pid_%d for %s :does not exists\n", i, arvg[I]);
            //I don't know how to write int into the pipe,so below might be wrong
            write(STDOUT_FILENO, words, 1);
            
            exit(1);
         }
      } else {
         close(*write_fd);

         //and I have no idea how to read int from pipes
         read(*read_fd, &readbuffer, 1);

         totalwords += ???
         close(*read_fd);
         //Wait until all child processes exit/return
         if (ppid == getpid()) {
            wait( & status);
         }
         //inspect their exit codes, WEXITSTATUS = return code when child exits
         if (WEXITSTATUS(status) == 1) {
            count++;
         }
      }
   }
   printf("Main process created %d child processes to count words in %d files\n", argc - 1, argc - 1);
   printf("Total words is %d", totalwords);
   printf("%d files have been counted sucessfully!\n", argc - 1 - count);
   printf("%d files did not exist.\n", count);

   return 0;
}```

Can someone help me to figure out this? I don't really know how to achieve my goal with pipe.

Ответы [ 2 ]

0 голосов
/ 10 июля 2020

Ну первое время я не акцентировал внимание на al go. Я все это исправил. Проблема заключается в разветвлении al oop, и чтение и запись приведут к неверным результатам. Более того, родительский элемент должен искать EOF, чтобы убедиться, что все операции чтения были выполнены. В любом случае, вот код, который должен работать


    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    #define MAX_CHAR 100
    
    pid_t getpid(void);
    pid_t getppid(void);
    
    char* itoa(int i, char b[]){
        char const digit[] = "0123456789";
        char* p = b;
        if(i<0){
            *p++ = '-';
            i *= -1;
        }
        int shifter = i;
        do{ //Move to where representation ends
            ++p;
            shifter = shifter/10;
        }while(shifter);
        *p = '\0';
        do{ //Move back, inserting digits as u go
            *--p = digit[i%10];
            i = i/10;
        }while(i);
        return b;
    }
    
    // count word from file provided
    int countWords(char * fp, int pid) {
       FILE * file;
       int words = 0;
       char word[MAX_CHAR];
       //execute this function only if child process of parent, no gradchild is allowed to execute this function!
       if (pid == getppid()) {
          file = fopen(fp, "r");
          if (file == NULL) {
             return -1;
          }
          //find string in the file and count the words.
          while (fscanf(file, "%s", word) != EOF) {
             words++;
          }
          return words;
       } else {
          return -1;
       }
       return 0;
    }
    
    //do everything related to child here in this function
    void child_process(int write_fd, char *filename, int ppid)
    {
        // call a function to count the number of words in file argv[i]
        printf("counting words of %s\n", filename);
        int words = countWords(filename, ppid);
        if (words >= 0) {
            printf("Child process pid for %s :number of words is %d\n", filename, words);
            write(write_fd, (void *)&words, 1);
            close(write_fd);
            exit(0);
        } else if (words == -1) {
            printf("Child process pid for %s :does not exist\n", filename);
            write(STDOUT_FILENO, (void *)&words, 1);
            close(write_fd);
            exit(1);
        }
        return;
    }
    
    int main(int argc, char * argv[]) {
       //if invalid arguments
       if (argc < 2) {
          fprintf(stderr, "ERROR: INVALID ARGUMENTS");
          exit(-1);
       }
    
       int pid = 0;
       int ppid = 0;
       int totalwords = 0;
       int fd[2] = {0};
       int write_fd = 0;
       int read_fd = 0;
       int recvd = 0;
    
       // open a pipe
       if(-1 == pipe(fd)){
         perror("pipe");
         return -1;
       }
    
       // assign write_fd and read_fd
       write_fd = fd[1];
       read_fd = fd[0];
    
       //parent pid
       ppid = getpid();
    
       //each child process to count the number of words in each file
       pid = fork();
       for (int i = 0; i < argc-1; i++)
       {
           //child process
           if (pid == 0) {
               close(read_fd);
               child_process(write_fd, argv[i+1], ppid);
               break;
           } else {
               pid = fork();
           }
    
       }
    
       // don't let child run beyond this point
       if (pid == 0) {
           exit(0);
       }
    
       // parent only code
       if (pid > 0)
       {
           close(write_fd);
           while (read(read_fd, (void*)&recvd, 1) > 0) 
           {
               wait(NULL);
               totalwords += recvd;
           }
           close(read_fd);
       } 
       printf("Main process created %d child processes to count words in %d files\n", argc - 1, argc - 1);
       printf("Total words is %d\n", totalwords);
       printf("%d files have been counted sucessfully!\n", argc - 1);
    }

0 голосов
/ 10 июля 2020

обнаружил некоторые проблемы с кодом. Я исправил их для вас (однако я бы сделал то же самое, немного по-другому)

  1. чтение и запись int из канала довольно прямолинейно, просто правильно приведите тип при чтении или записи в int.

  2. mallo c в pid не было необходимости. Также mallo c возвращает указатель и должен иметь тип (int *)

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

Достаточно сказать, вот ваш рабочий код


    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    #define MAX_CHAR 100
    
    pid_t getpid(void);
    pid_t getppid(void);
    
    char* itoa(int i, char b[]){
        char const digit[] = "0123456789";
        char* p = b;
        if(i<0){
            *p++ = '-';
            i *= -1;
        }
        int shifter = i;
        do{ //Move to where representation ends
            ++p;
            shifter = shifter/10;
        }while(shifter);
        *p = '\0';
        do{ //Move back, inserting digits as u go
            *--p = digit[i%10];
            i = i/10;
        }while(i);
        return b;
    }
    int countWords(char * fp, int pid) {
       FILE * file;
       int words = 0;
       char word[MAX_CHAR];
       //execute this function only if child process of parent, no gradchild is allowed to execute this function!
       if (pid == getppid()) {
          file = fopen(fp, "r");
          if (file == NULL) {
             return -1;
          }
          //find string in the file and count the words.
          while (fscanf(file, "%s", word) != EOF) {
             words++;
          }
          return words;
       } else {
          return -1;
       }
       return 0;
    }
    
    int main(int argc, char * arvg[]) {
       //if invalid arguments
       if (argc < 2) {
          fprintf(stderr, "ERROR: INVALID ARGUMENTS");
          exit(-1);
       }
    
       int count = 0, pid, ppid, status, totalwords = 0;
       
       int result = -1;
       int fd[2];
       char string[100];
       char readbuffer[80];
       int *write_fd = &fd[1];
       int *read_fd = &fd[0];
       int recvd = 0;
       result = pipe(fd);
       if(-1 == result){
         perror("pipe");
         return -1;
       }
       //creates (argc - 1) child processes using fork()
       //pid = (int) malloc((argc - 1) * sizeof(int));
       //parent pid
       ppid = getpid();
    
       //each child process to count the number of words in each file
       for (int i = 1; i < argc; i++) {
          //child process
          pid = fork();
          if( pid == -1){
              perror("failed to fork");
              return -1;
          }else if (pid == 0) {
              printf ("%d child running \n", i);
             // call a function to count the number of words in file arvg[i]
             int words = countWords(arvg[i], ppid);
             close(*read_fd);
             if (words >= 0) {
                printf("Child process pid_%d for %s :number of words is %d\n", i, arvg[i], words);
                //I don't know how to write int into the pipe,so below might be wrong
                write(*write_fd, (void *)&words, 1);
              
                return 0;
             } else if (words == -1) {
                printf("Child process pid_%d for %s :does not exists\n", i, arvg[i]);
                //I don't know how to write int into the pipe,so below might be wrong
                write(STDOUT_FILENO, (void *)&words, 1);
                
                exit(1);
             }
          } else {
             close(*write_fd);
    
             //and I have no idea how to read int from pipes
             read(*read_fd, (void*)&recvd, 1);
    
             totalwords += recvd;
             printf("recvd %d \n", totalwords);
             close(*read_fd);
             //Wait until all child processes exit/return
             if (ppid == getpid()) {
                wait( & status);
             }
             //inspect their exit codes, WEXITSTATUS = return code when child exits
             if (WEXITSTATUS(status) == 1) {
                count++;
             }
          }
       }
       printf("Main process created %d child processes to count words in %d files\n", argc - 1, argc - 1);
       printf("Total words is %d\n", totalwords);
       printf("%d files have been counted sucessfully!\n", argc - 1 - count);
       printf("%d files did not exist.\n", count);
    
       return 0;
    }

...