无法在C中的管道中写入两次

时间:2014-11-27 18:05:34

标签: c pipe ipc

我编写了一个简短的C程序,以便学习IPC基础。该程序包含一个子进程,它试图向管道和父进程写入两次,该进程尝试读取这两个消息。邮件位于text1text2。执行后,父进程只读取第一条消息。

子进程的输出如下:

I write text1 in pipe
I write text2 in pipe

通过管道从子级接收的父级文本为:Hi Dady, I'm your child and text1!

以下是代码:

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);}

为什么我只阅读text1

1 个答案:

答案 0 :(得分:1)

这个问题比AB_的答案更糟糕。 (现已删除:此答案建议再做一次阅读)

父母和孩子之间可能存在竞争条件。如果孩子只能在父母阅读第一条信息之前写一次,那么一切都会好的(如果你读了两次)。但如果孩子在父母阅读之前写了两次,那么第一次(或唯一)阅读会得到72个字符......但是你只会打印第一条消息!

为了证明这一点,我略微修改了父部分,等待0.5秒并显示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);     }

我得到了:

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!

为什么它会获得72个字符并仅在上半部分打印?因为readbuffer[36] == '\0'!并且所有C字符串函数都使用NULL作为字符串终止符。

因此当你在管道或套接字中传递文本时,规则是,除非你对它们进行特殊处理,否则永远不要发送终止空值(*)

你应该在孩子身上使用:

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

仅发送非空字符并避免竞争条件的风险。

(*)根据Mat的评论编辑:在串行通道(管道,插座或...串行线)中,您必须使用大小+数据或分隔符来清楚地标识数据块。我通常避免使用NULL作为分隔符(在C或C ++程序中),因为它阻止了所有字符串函数的使用。但是你要处理它并继续处理超过第一个null,NULL是一个很好的分隔符,因为它没有在文本中使用(这就是为什么它是C分隔符)。

并且不要忘记:单个读取的大小(至少在串行线和管道上)可以大于或小于单个写入的大小:这里,例如,睡眠连接两个写入。