问题描述
我有两个独立的 C++ 程序,一个以不可预测的时间间隔写入两个命名管道,另一个应该等待从管道中读取新内容。为简单起见,我的作者在这里只向管道写入两次(第一次:“一”“树”,第二次:“两个”“雾”)。
我的作家程序是:
#include <unistd.h>
#include <iostream>
int main()
{
int fd1,fd2;
const char* myfifo1 = "/tmp/myfifo1";
const char* myfifo2 = "/tmp/myfifo2";
mkfifo(myfifo1,0666);
mkfifo(myfifo2,0666);
fd1 = open(myfifo1,O_WRONLY);
fd2 = open(myfifo2,O_WRONLY);
write(fd1,"One",sizeof("One"));
write(fd2,"Tree",sizeof("Tree"));
sleep(5);
write(fd1,"Two",sizeof("Two"));
write(fd2,"Fogs",sizeof("Fogs"));
close(fd1);
close(fd2);
unlink(myfifo1);
unlink(myfifo2);
}
我的阅读器程序是:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd1,fd2;
const char * myfifo1 = "/tmp/myfifo1";
const char * myfifo2 = "/tmp/myfifo2";
char buf1[MAX_BUF],buf2[MAX_BUF];
fd1 = open(myfifo1,O_RDONLY);
fd2 = open(myfifo2,O_RDONLY);
while (1) {
read(fd1,buf1,MAX_BUF);
read(fd2,buf2,MAX_BUF);
printf("Received: %s\n",buf1);
printf("Received: %s\n",buf2);
}
close(fd1);
close(fd2);
return 0;
}
我不希望读取器终止或关闭读取之间的连接,我需要它保持活动状态并等待写入器在命名管道中写入新内容。 但是,通过同时运行这两个程序(在不同的内核中,首先是写入器,然后是读取器),我得到:
Received: One
Received: Tree
Received: Two
Received: Fogs
Received: Two
Received: Fogs
Received: Two
Received: Fogs
Received: Two
Received: Fogs
...
...
想要的行为是:
Received: One
Received: Tree
Received: Two
Received: Fogs
然后什么都没有(读者应该等待另一个写入)。
我知道我应该在读取后以某种方式清除缓冲区,但这不是读取的默认行为吗?既然读完了《二》(还有《迷雾》),为什么还要继续读,不等新内容?
我应该做哪些修改?
在此先非常感谢您!
解决方法
关闭管道向另一端发出文件结束信号。
read
将在遇到文件结束条件时读取零字节(并返回零)。文件结束后的任何后续读取都是空操作。
如果想继续从同一个管道读取,需要检查read
的结果,如果返回零,关闭管道再打开。
当然,如果您需要其他人继续使用管道,则不应unlink
。
要注意的另一件事:read
(1) 不会以 0 字节终止缓冲区,并且 (2) 不一定读取单个 {{1} 写入的确切字节数}}。您应该自己检测消息的结尾,而不是依赖 write
和 read
来为您检测。完全有可能 write
会读取没有终止空字符的字符串的一半,然后您的 read
将打印垃圾。