简体   繁体   中英

Can't write twice into a pipe in C

I code a short C program in order to learn IPC basis. The program consists of a child process trying to write twice to a pipe and parent process which tries to read both messages. The messages are in text1 and text2 . After executing, parent process reads only the fist message.

Output of child process is as follows:

I write text1 in pipe
I write text2 in pipe

Text received in parent from child through pipe is: Hi Dady, I'm your child and text1! .

Here is the code:

main(void){
    int     fd0[2], nbytes;
    pid_t   childpid;
    ssize_t errorfi;
    char    text1[] = "Hi Dady, I'm your child and text1!\n";
    char    text2[] = "Hi Dady, I'm your child and text2!\n";
    char    readbuffer[80],msg[80];
    pipe(fd0);        
    if((childpid = fork()) == -1)
    {
            perror("fork");
            _exit(1);
    }
    if(childpid == 0)
    {       //child process
            close(fd0[0]);
            fprintf (stderr, "I write text1 in pipe\n");
            errorfi = (write(fd0[1], text1, (strlen(text1)+1)));
            if (errorfi <0 )
            {
               fprintf (stderr, "errorfi = %d\n", errorfi);
               fprintf (stderr, "error writting texto1 in fd0 pipe %s\n",strerror(errorfi));
               _exit (EXIT_FAILURE);
            }
            fprintf (stderr, "I write text2 in pipe\n");
            errorfi = (write(fd0[1], text2, (strlen(text2)+1)));
            if (errorfi <0 )
            {
               fprintf (stderr, "errorfi = %d\n", errorfi);
               fprintf (stderr, "error writting texto2 in fd0 pipe %s\n",strerror (errorfi));
               _exit (EXIT_FAILURE);
             }
           _exit(0);
    else
    {       //parent process
            close(fd0[1]);
            nbytes = read(fd0[0], readbuffer, sizeof(readbuffer));
            printf("text received in parent from child trough pipe:%s\n", readbuffer);
    }
    return(0);}

Why do I only read text1 ?

The problem is worse than the answer from AB_ let think. (Now deleted : this answers advised to do a second read)

You may have a race condition between parent and child. If child can only write once before parent reads first message, all will be fine (provided you read twice). But if child write twice before parent reads the first (or only) read will get the 72 characters ... but you will only print the first message !

To demonstrate that, I slightly modified the parent part, waiting 0.5 seconds and displaying nbytes :

{       //parent process
        close(fd0[1]);
        usleep(500);
        nbytes = read(fd0[0], readbuffer, sizeof(readbuffer));
        printf("text received in parent from child trough pipe (%d) :%s\n",

nbytes, readbuffer); }

And I get :

I write text1 in pipe
I write text2 in pipe
text received in parent from child trough pipe (72) :Hi Dady, I'm your child and text1!

Why does it get 72 characters and prints only first half ? Because readbuffer[36] == '\\0' ! And all C string functions use that NULL as the string terminator.

So the rule is when you pass text in pipe or through sockets, never ever send the terminating nulls unless you do special processing for them (*)

You should use in child :

errorfi = write(fd0[1], text2, strlen(text1));

to only send non null characters and avoid the risk of race condition.

(*) Edited per Mat's comment : in a serial channel (pipe, socket or ... serial line), you must use either size + data or a delimiter to clearly identify blocks of data. I generally avoid NULL as delimiter (in C or C++ programs) because it blocks usage of all string functions. But it you take care of it and continue processing beyond first null, NULL is an excellent delimiter as it is not used in text (that's the reason why it is C delimiter).

And do not forget : the size of a individual read (at least on serial line and pipe) can be greater or lesser than the size of the individual writes : here the sleep concatenates the two writes for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM