Nawar Youssef
Nawar Youssef

Reputation: 83

Why the parent process read only the first and sixth message from a child process?

I am trying to send ten messages from a child process to the parent. But the output of the program shows that parent process read the first and sixth messages only. I tried to change the sleep() position in the code, also I tried to use while() to read instead of for() but the problem remains the same. Here is the code:

int main(int argc, char *argv[]){

char ch, message_from_A[100], message_from_B[100], msg_to_log[100], msg_to_B[100];
int i, x, fd_log[2], fd_A_B[2], fd_B_C[2], fd_B_D[2];
pipe(fd_log);

//fork process A
if (fork()==0) { //child
    printf("Inside process A\n");
    for (i=0; i < 10; i++) {
        //creat new msg
        x = (rand() % 2);
        if (x == 1)
            ch='C';
        else
            ch='D';

        //write msg to log pipe
        sprintf(msg_to_log, "A sent to B: %c %d\n", ch, i);
        printf("wirtten to log pipe--> %s\n", msg_to_log);
        close(fd_log[READ]);
        write(fd_log[WRITE], msg_to_log, strlen(msg_to_log)+1);
    }//end for()
    close(fd_log[WRITE]); //this line won't affect output
    _exit(1);

} else { //parent

    printf("Inside process log\n");
    close(fd_log[WRITE]);
    while ( read(fd_log[READ], message_from_A, 100) > 0 ) {
        sleep(1);
        printf("\nmsg from A: %s", message_from_A);
    }
    close(fd_log[READ]); //this line won't affect output
}}

The output of this program shows the parent reads only the first and sixth messages! This is the output:

Inside process log

Inside process A

wirtten to log pipe--> A sent to B: C 0

wirtten to log pipe--> A sent to B: C 1

wirtten to log pipe--> A sent to B: C 2

wirtten to log pipe--> A sent to B: D 3

wirtten to log pipe--> A sent to B: D 4

wirtten to log pipe--> A sent to B: D 5

wirtten to log pipe--> A sent to B: D 6

wirtten to log pipe--> A sent to B: D 7

wirtten to log pipe--> A sent to B: C 8

wirtten to log pipe--> A sent to B: C 9

msg from A: A sent to B: C 0

msg from A: B: D 5

I appreciate any ideas or suggestions.

Upvotes: 1

Views: 137

Answers (2)

Arjun Mathew Dan
Arjun Mathew Dan

Reputation: 5298

The culprit here seems to be this line:

write(fd_log[WRITE], msg_to_log, strlen(msg_to_log)+1);

That should be:

write(fd_log[WRITE], msg_to_log, strlen(msg_to_log));

Else you are sending an extra character (which will be '\0', msg_to_log being global).. Hence eventhough the read() succeeds, it won't print the whole sequence of characters(but only until the '\0'). Also memset msg_to_log before filling it in each time (to make sure none of the old characters are hanging in there). Also memset message_from_A after each print (for the same reason).

Also, move close(fd_log[READ]); before the for loop.

Upvotes: 1

Michael Burr
Michael Burr

Reputation: 340336

In the child you are writing several blocks of data that look something like:

A sent to B: C x

each followed by a null character (the 'x' above is replaced by a number indicating the line of data written to the pipe). However the process that is reading the pipe will read whatever has been put into the pipe up to the limit specified in the read() function call - it doesn't stop at the null character. So the first read() might grab the first 100 characters from the following that might be in the pipe:

A sent to B: C 0\0A sent to B: C 1\0A sent to B: C 2\0A sent to B: C 3\0A sent to B: C 4\0A sent to B: C 5\0

However, when the parent displays what is read from the pipe, it prints it as a null terminated string, so only the first part of the buffer is displayed.

Then the next read picks up the fragment that was left in the pipe (and anything after that fragment), and again displays only until the null character.

To fix the problem use the return code from read() to figure out what has been returned, and deal appropriately with the null characters.

Upvotes: 3

Related Questions