我有一个简单的C++应用程序,它应该从一个POSIX命名管道中读取行:
#include<iostream>
#include<string>
#include<fstream>
int main() {
std::ifstream pipe;
pipe.open("in");
std::string line;
while (true) {
std::getline(pipe, line);
if (pipe.eof()) {
break;
}
std::cout << line << std::endl;
}
}
步骤:
我创建了一个命名管道:
mkfifo in
。我使用
g++ -std=c++11 test.cpp && ./a.out
编译并运行C++代码。我向
in
管道发送数据:
sleep infinity > in & # keep pipe open, avoid EOF
echo hey > in
echo cats > in
echo foo > in
kill %1 # this closes the pipe, C++ app stops on EOF
在Linux下执行此操作时,应用程序成功显示每个echo
命令后的输出(g++ 8.2.1)。
当尝试在macOS上完成整个过程时,只有在关闭管道后(即在kill %1
之后)才会显示输出。我开始怀疑存在某种缓冲问题,因此我尝试禁用它,就像这样:
std::ifstream pipe;
pipe.rdbuf()->pubsetbuf(0, 0);
pipe.open("out");
通过这个更改,在第一个echo
之后,应用程序不会输出任何内容,然后在第二个echo
之后打印出第一条消息("hey"),并且始终落后于一条消息,并显示前一个echo
的消息而不是已执行的消息。
只有在关闭管道后才显示最后一条消息。
我发现在macOS上,g++
基本上是clang++
,因为g ++ --version
得出:"Apple LLVM version 10.0.1(clang-1001.0.46.3)"。
在使用Homebrew安装真正的g++之后,示例程序可以正常工作,就像在Linux上一样。
我正在构建一个简单的IPC库,以命名管道为基础,这对我来说几乎是一个要求,因此正确工作非常重要。
当使用LLVM时,是什么导致了这种奇怪的行为?(更新:这是由libc++引起的)
这是一个错误吗?
这种方式是否以某种方式由C++标准保证在g ++上工作?
如何使用clang++
使此代码段正常工作?
更新:
这似乎是由getline()
的libc++实现引起的。
相关链接:
但问题仍然存在。
std::getlines()
不会阻塞。使用 DOS 换行符也会产生相同的结果。 - krispet krispet_LIBCPP_VERSION
为1101时,能够看到期望的行为。 - Davis Herringstd::getline()
的奇怪行为,而不是我读取命名管道直到定界符的原因。 - krispet krispetfstream
行为的规定。但是没关系,我在发布后几天就自己解决了这个问题,我会发布我的解决方案以帮助其他人。 - krispet krispet