我的 C++ 程序如何等到对命名管道进行新的写入?
Posted
技术标签:
【中文标题】我的 C++ 程序如何等到对命名管道进行新的写入?【英文标题】:How can my C++ program wait until a new write has been made to the named pipe? 【发布时间】:2021-03-18 14:43:40 【问题描述】:我在 C++ 中有两个独立的程序,一个以不可预测的间隔写入两个命名管道,另一个应该等待从管道中读取新内容,只要可用。为简单起见,这里我的作者只写了两次管道(第一次:“One”“Tree”,第二次:“Two”“Fogs”)。
我的作家计划是:
#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
不再阅读旧消息,它出错了。如果您检查每个 I/O 操作的结果,您就会知道,这是您应该做的。
您可能也有兴趣查看select,而不是让您的读者忙于等待新消息。
读出错误,你的程序不会寻找错误,因为出现错误,buf1和buf2的内容没有更新,所以你的程序打印旧的内容。
您的帖子被标记为 C++,但代码是 C。您的意思是将其标记为 C 吗?
@NathanPierson 它是阻塞读取而不是忙等待。但稍微复杂一点的应用程序会使用select()
同时阻塞多个管道,以便其中一个可用。
【参考方案1】:
关闭管道将文件结束信号发送到另一端。
read
在遇到文件结束条件时将读取零字节(并返回零)。文件结尾之后的任何后续读取都是空操作。
如果要继续从同一个管道读取,需要检查read
的结果,如果返回零,关闭管道再打开。
如果您需要其他人继续使用它,当然不应该unlink
管道。
还有一点需要注意:read
(1) 不会以 0 字节终止缓冲区,并且 (2) 不一定会读取单个 write
写入的确切字节数。您应该自己检测消息结束,而不是依靠read
和write
为您完成。 read
完全有可能读取字符串的一半而没有终止空字符,然后您的 printf
将打印垃圾。
【讨论】:
当阅读器不知道应该读取的字节数时,如何检测到消息结束?一种方法是作者计算此数字并在消息之前将其发送给读者。还有另一种更简单的方法吗?请帮忙。谢谢。 API 中没有消息。您需要设计一个实现消息的协议。在消息长度之后发送消息是一种可能的方法。如果要发送 C 字符串,您可能希望在发送端发送一个 0 终止符并在接收端 检测它,这是另一种方式。以上是关于我的 C++ 程序如何等到对命名管道进行新的写入?的主要内容,如果未能解决你的问题,请参考以下文章
命名管道上的 WriteFile 有时会返回 ERROR_NO_DATA