'Read and write using pipes

I have a program with 2 child processes which has to do the following:

  • use the parent to read data from a file 'data.txt' and write in a pipe
  • use a child to read the data from the pipe and filter the lowercase letters
  • use another child to write the filtered letters in a new file, each on a new line

I tried to do it and it works... kinda. The problem is, it writes the filtered letters in the desired file, but the program does not stop. What am I doing wrong?

    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #include <string.h>
    
    int parentChildpipeFileDescriptors[2], child1Child2FileDescriptors[2];
    
    void parentProcess()
    {
        close(child1Child2FileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
        close(parentChildpipeFileDescriptors[0]);
    
        int fileDescriptor = open("data.txt", O_RDONLY);
        char buffer[8];
        int store;
        while ((store = read(fileDescriptor, buffer, 8)))
        {
            write(parentChildpipeFileDescriptors[1], buffer, store);
        }
        close(fileDescriptor);
    
        close(parentChildpipeFileDescriptors[1]);
    }
    
    void child1Process()
    {
        close(parentChildpipeFileDescriptors[1]);
        close(child1Child2FileDescriptors[0]);
    
        char buffer[8];
        int store, count = 0;
        while ((store = read(parentChildpipeFileDescriptors[0], buffer, 8)))
        {
            for (int i = 0; i < store; i++)
            {
                if (buffer[i] >= 'a' && buffer[i] <= 'z')
                {
                    count++;
                    write(child1Child2FileDescriptors[1], &buffer[i], sizeof(buffer[i]));
                }
            }
        }
        printf("CHILD 1 FINISHED FILTERING\n");
    
        close(parentChildpipeFileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
    
        exit(count);
    }
    
    void child2Process()
    {
        close(parentChildpipeFileDescriptors[0]);
        close(child1Child2FileDescriptors[1]);
    
        mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
        char *fileName = "stat.txt";
        int newFileDescriptor = creat(fileName, mode);
        char buffer;
        int store;
        while ((store = read(child1Child2FileDescriptors[0], &buffer, 1)))
        {
            write(newFileDescriptor, &buffer, sizeof(buffer));
            write(newFileDescriptor, "\n", 1);
        }
        close(newFileDescriptor);
    
        printf("CHILD 2 FINISHED WRITING'\n");
    
        close(child1Child2FileDescriptors[0]);
        close(parentChildpipeFileDescriptors[1]);
    
        exit(444);
    }
    
    int main(int argc, char const *argv[])
    {
        if (pipe(parentChildpipeFileDescriptors) < 0)
        {
            printf("ERROR CREATING PIPE\n");
            exit(-100);
        }
    
        if (pipe(child1Child2FileDescriptors) < 0)
        {
            printf("ERROR CREATING PIPE\n");
            exit(-101);
        }
    
        pid_t child1PID = fork();
        if (child1PID < 0)
        {
            printf("ERROR CREATING CHILD\n");
            exit(-200);
        }
        if (!child1PID)
        {
            child1Process();
        }
    
        pid_t child2PID = fork();
        if (child2PID < 0)
        {
            printf("ERROR CREATING CHILD\n");
            exit(-201);
        }
        if (!child2PID)
        {
            child2Process();
        }
    
        parentProcess();
        int status1, status2;
        waitpid(child1PID, &status1, 0);
        waitpid(child2PID, &status2, 0);
        printf("CHILD 1 TERMINATED WITH EXIT STATUS: %d\n", WEXITSTATUS(status1));
        printf("CHILD 2 TERMINATED WITH EXIT STATUS: %d\n", WEXITSTATUS(status2));
    
        return 0;
    }


Solution 1:[1]

your while ((store = read(parentChildpipeFileDescriptors[0], buffer, 8))) loop is never gonna end.

The parent needs to say to the child that there is no more data coming and it shall not do another read. You can do this by sending a special byte.

Example :

in the parent:

char endByte = 0x1;
write(parentChildpipeFileDescriptors[1], &endByte, 1);
//then close

in the while loop of the child :

if(buffer[i] ==  0x1){
    printf("CHILD 1 FINISHED FILTERING\n");
    fflush(stdout);
    close(parentChildpipeFileDescriptors[0]);
    close(child1Child2FileDescriptors[1]);

    exit(count);
};

Solution 2:[2]

Aggregation filter example playground

Code:

 db.collection.aggregate([
   {
     $match: {
       "retval.date_year": {
       $gte: 2014
     }
    }
   },
  {
   $project: {
      retval: {
        $filter: {
          input: "$retval",
          as: "item",
          cond: {
            $gte: [
              "$$item.date_year",
              2014
            ]
          }
        }
      }
     }
   }
  ])

explained:

  1. You match only the documents with with the desired year in messages inside retval array.
  2. Project only those messages from desired year.

Hint: It is best to create index on "retval.date_year" field for best results.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 R2D2