我有一个简单的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上执行此操作时,应用程序会按预期(g ++ 8.2.1)在每个echo
命令之后成功显示输出。
在macOS上尝试整个过程时,仅在关闭管道之后(即在kill %1
之后)显示输出。
我开始怀疑某种缓冲问题,所以我尝试像这样禁用它:
std::ifstream pipe;
pipe.rdbuf()->pubsetbuf(0, 0);
pipe.open("out");
进行此更改后,应用程序在第一个echo
之后不输出任何内容,然后在第二个echo
之后打印出第一条消息(“嘿”),并继续这样做,将消息滞后并显示前一个echo
的消息,而不是已执行的消息。
仅在关闭管道后显示最后一条消息。
我发现在macOS g++
上基本上是clang++
,因为
g++ --version
产生:“ Apple LLVM版本10.0.1(clang-1001.0.46.3)”。
在使用Homebrew安装了真正的g ++之后,该示例程序就可以正常工作,就像在Linux上一样。
出于各种原因,我正在建立一个基于命名管道的简单IPC库,因此,对于我来说,这是正常工作的必要条件。
使用LLVM时,是什么导致这种奇怪的行为?(更新:这是由libc ++引起的)
这是一个错误吗?
以某种方式保证C ++标准在g ++上的工作方式吗?
如何使用clang++
使此代码段正常工作?
更新:
这似乎是由getline()
的libc ++实现引起的。
相关链接:
问题仍然存在。
答案 0 :(得分:1)
我已通过将POSIX getline()
包装在简单的C API中并从C ++进行简单调用来解决此问题。
代码是这样的:
typedef struct pipe_reader {
FILE* stream;
char* line_buf;
size_t buf_size;
} pipe_reader;
pipe_reader new_reader(const char* pipe_path) {
pipe_reader preader;
preader.stream = fopen(pipe_path, "r");
preader.line_buf = NULL;
preader.buf_size = 0;
return preader;
}
bool check_reader(const pipe_reader* preader) {
if (!preader || preader->stream == NULL) {
return false;
}
return true;
}
const char* recv_msg(pipe_reader* preader) {
if (!check_reader(preader)) {
return NULL;
}
ssize_t read = getline(&preader->line_buf, &preader->buf_size, preader->stream);
if (read > 0) {
preader->line_buf[read - 1] = '\0';
return preader->line_buf;
}
return NULL;
}
void close_reader(pipe_reader* preader) {
if (!check_reader(preader)) {
return;
}
fclose(preader->stream);
preader->stream = NULL;
if (preader->line_buf) {
free(preader->line_buf);
preader->line_buf = NULL;
}
}
这对libc ++或libstdc ++很好。
答案 1 :(得分:0)
如单独讨论的那样,最好使用switch_source()
解决方案,但是您的问题特别是关于def switch_source(self, *args):
y = self.height
y1 = self.width / 2
self.ids.test.pos = 0, y - y1
self.ids.test.source = 'redball.png'
是如何被阻止的,因此我将对此进行讨论。
这里的问题是,boost::asio
并不是真正用于FIFO文件类型的。在getline
的情况下,它试图进行缓冲读取,因此(在初始情况下)它确定缓冲区没有足够的数据到达定界符(std::ifstream
),调用{{ 1}}放在基础getline()
上,这样就可以轻松读取缓冲区长度的数据。这对于文件非常有用,因为文件在某个时间点的长度是一个已知的长度,因此,如果没有足够的数据来填充缓冲区,则可以返回EOF;如果有足够的数据,则仅返回已填充的缓冲区。但是,对于FIFO,用完数据并不一定意味着'\n'
,因此直到写入它的进程关闭时它才返回(这是使它保持打开状态的无限underflow()
命令)
执行此操作的一种更典型的方法是让编写器在读写文件时打开和关闭文件。当提供streambuf
/ EOF
之类的功能更强大的功能时,这显然是在浪费精力,但是我在回答您要问的问题。