Question

I have a problem when trying to answer an exercice, that requires that a first process writes into a pipe line by line, and that a second process reads from that pipe from a buffer of only 20 bytes. It seems that some information get "lost" in the pipe and the input lacks random bits of the initial message. Here is the code related to the problem :

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

#define BUFF_SIZE 20
#define LINE_SIZE 150


int main(){

    pid_t idp1, idp2;
    int pipefd[2];
    if (pipe(pipefd) == -1) return 3; //Pipe error


    if ((idp1 = fork()) == 0){

        //SON 1
        close(pipefd[0]);
        FILE* input = fopen("input.txt", "r");
        char line[LINE_SIZE];

        //Get a line
        while(fgets(line, LINE_SIZE, input)){ 


            //Sends the line
            write(pipefd[1], line, LINE_SIZE);
            sleep(1);
        }
        fclose(input);
        close(pipefd[1]);

    }else if(idp1 != -1){

        if ((idp2 = fork()) == 0){

            //SON 2
            close(pipefd[1]);
            char inMsg[BUFF_SIZE] = "";
            int received;

            while(received = read(pipefd[0], inMsg, BUFF_SIZE)){
                inMsg[received] = '\0';
                printf("%.*s", received, inMsg);
            }

        }else if(idp2 != -1){

            //Father
            close(pipefd[0]);
            close(pipefd[1]);
            //SleepOrWhatever();

        }else return 2; //Fork 2 error

    }else return 1; //Fork 1 error

    return 0;

}

Now, by adding a delay (the sleep after the input of each line into the pipe), it solves the problem. Why is that ? And is there anyway to avoid this ? Here is the result in the shell with the sleep and without :

[010][input.txt]
[049][[Fichier d'entrée du programme TD0 forkpipe.c].]
[001][]
[054][[003]Il contient des lignes [de longueurs variables].]
[041][avec des lignes blanches (longuer [000])]
[001][]
[009][d'autres]
[020][         commencant]
[036][                    par des blancs.]
[010][et enfin,]
[021][une dernière ligne.]


[010][input.txt]
hier d'entrée du programme TD0 forkpipe.c].]
[001][]
]Il contient des lignes [de longueurs variables].]
[041][avec des lignes blanches (longuer [000])]
[009][d'autres]
     commencant]
[036][                    par des blancs.]
nfin,]
[021][une dernière ligne.]

PS : I also tried reading with greater buffer size from the pipe, and everything outputs fine. I am also running on a linux distribution, if it has any importance in the behavior of pipes.

Was it helpful?

Solution

Consider what is happening when reading the input from the file, namely:

//Get a line
while(fgets(line, LINE_SIZE, input)){ <<-- fgets reads a line _up_ to a LINE_SIZE bytes (and the result will be null terminated)


    //Sends the line
    write(pipefd[1], line, LINE_SIZE); <<-- Write LINE_SIZE bytes to the pipe
}

So, given a few lines in your file, you may read e.g. 60 bytes with fgets, and then you write 150 bytes to the pipe (meaning 90 bytes of garbage goes there too).

You end up with this:

INPUT:

first line
second line
third line

Pipe data:

first line***second line*** third line ***

Where the *** symbolizes the garbage data written to the pipe. Once the second process starts reading, depending on the garbage data, it may print whatever it wants.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top