2

我正在尝试使用 fifo 在两个进程之间来回发送信息。它可以工作到一定程度,但随后会出现读取块。我怀疑 Process2 是错误所在。

过程1:

#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
main()
{
 char oprtr;
 int fd1,fd0;
 float oprnd1,oprnd2,result;

 mkfifo("fifo1",0777);
 fd1=open("fifo1",O_RDWR);

 printf("fd1:%d\n",fd1);
 printf("Add(+)\n");
 printf("subtract(-)\n");
 printf("multiply(*)\n");
 printf("division(/)\n");

 printf("Enter operator\n");
 scanf("%c",&oprtr);
 getchar();
 write(fd1,&oprtr,sizeof(oprtr));

 printf("Enter oprnd1\n");
 scanf("%f",&oprnd1);
 getchar();
 write(fd1,&oprnd1,sizeof(oprnd1));

 fd0=dup(fd1);
 printf("Enter oprnd2\n");
 scanf("%f",&oprnd2);
 getchar();

 if(write(fd0,&oprnd2,sizeof(oprnd2))==0)
  perror("write : oprnd2:");
 else
  printf("writing oprnd2 done\n");

 read(fd1,&result,sizeof(result));
 printf("Result:%f\n",result);
}

过程2:

#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
main()
{
 int fd2,fd3;
 char oprtr;
 float oprnd1,oprnd2,result;
 fd2=open("fifo1",O_RDWR);
 printf("fd2:%d\n",fd2);

 read(fd2,&oprtr,sizeof(oprtr));
 printf("oprtr:%c\n",oprtr);

 read(fd2,&oprnd1,sizeof(oprnd1));
 printf("oprnd1:%f\n",oprnd1);

 fd3=dup(fd2);

这是读取功能被阻塞的地方

上面的两个 read() 调用似乎工作正常,但是下面的 read() 调用被阻塞了。为什么?

 if(read(fd3,&oprnd2,sizeof(oprnd2))==0) ////This is the problem
  perror("read : oprnd2:");
 else
  printf("oprnd2:%f\n",oprnd2);

switch(oprtr)
 {
 case '+':result=oprnd1+oprnd2;
          write(fd2,&result,sizeof(result));break;
 case '-':result=oprnd1-oprnd2;
          write(fd2,&result,sizeof(result));break;
 case '*':result=oprnd1*oprnd2;
          write(fd2,&result,sizeof(result));break;
 case '/':result=oprnd1/oprnd2;
          write(fd2,&result,sizeof(result));break;
 default: printf("Wrong Choice\n");break;
 }
}

1号航站楼:

Add(+)
subtract(-)
multiply(*)
division(/)
Enter operator
+
Enter oprnd1
14.56
Enter oprnd2
16.44
writing oprnd2 done
Result:16.440089

2号航站楼:

fd2:3
oprtr:+
oprnd1:14.560000

然后它就被阻塞了

4

1 回答 1

2

简短而简单的答案是,如果没有一些外部同步机制,您不应该使用单个 fifo 进行双向通信。

详细说明:Unix 管道或 fifo 不是最好的可视化管道类型管道。它更像是一个储罐,有管道进出它。标准用法是一个进程写入,从而填充容器,另一个进程读取,从而排空容器。在您的程序中,写入 fifo 的所有内容都放在容器中,直到有人出现并读取它,先到先得。因此,您的 Process1 程序读取 16.44 值,它从 写入oprnd2,回到result. 这使水箱空着,因此 Process2 没有任何内容可供读取。它归结为比赛条件。我怀疑,如果你运行这两个命令几百次,它们会按照你想要的方式运行几次。 

如果您只想要概念验证,请在来自 fifosleep之前添加一个到 Process1 。read更好的解决方案是使用两个 fifo,每个方向一个。或者您可以为 Process2 设计一些方法,让 Process1 知道它 (Process2) 已经读取了运算符和两个操作数并写入了结果——例如,一个信号或一个信号量——但这可能比它的价值更麻烦.

另一方面,我强烈建议不要在scanf玩具、演示或一次性原型类型的程序中使用。如果用户点击 just Enter,程序将永远坐在那里。我建议阅读一行(确保解决缓冲区溢出)然后调用sscanf它。

哦,还有,请缩进你的代码。

于 2013-01-25T03:17:30.413 回答