[英]Can't write twice into a pipe in C
我编写了一个简短的C程序,以学习IPC基础。 该程序由一个试图向管道写入两次的子进程和一个试图读取两条消息的父进程组成。 消息在text1
和text2
。 执行后,父进程仅读取第一条消息。
子进程的输出如下:
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
?
这个问题比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,读取缓冲区); }
我得到:
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作为字符串终止符。
因此,规则是当您通过管道或套接字传递文本时,除非对它们进行特殊处理 (*), 否则永远不要发送终止null。
您应该在孩子中使用:
errorfi = write(fd0[1], text2, strlen(text1));
仅发送非null字符并避免出现竞争状况的风险。
(*)根据Mat的评论进行编辑:在串行通道(管道,套接字或...串行线)中,必须使用size + data或定界符来清楚地标识数据块。 我通常避免使用NULL作为分隔符(在C或C ++程序中),因为它会阻止所有字符串函数的使用。 但是您要照顾好它并继续处理第一个null以外的内容,NULL是一个很好的分隔符,因为它不在文本中使用(这就是为什么它是C分隔符的原因)。
并且不要忘记:单个读取的大小(至少在串行线路和管道上)可以大于或小于单个写入的大小:例如,睡眠将两个写入连接在一起。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.