【发布时间】:2011-04-10 11:05:56
【问题描述】:
这个让我难过!
如果我使用async_read_until 调用,打印超过 4k 字节的内容似乎有问题?
我有一个小函数可以打印出 100 行(刚好超过 4k)。
除非我注册了async_read_until 回调,否则在每种组合中都可以正常工作。那时我的输出被截断到大约 4k。请注意,并非总是如此,有时打印较少,有时打印整个内容似乎与机器上的负载有关,几乎就像发生了一些超时?一些asio线程的东西?无论如何,如果我注释掉async_read_until 调用,无论我调用多少次printLines,它每次都能正常工作。我什至可以使用 ioService post 函数,它工作正常...
发生了什么事?顺便说一句,我使用的是 linux 和 amd64 机器 gcc4.4。 (红帽)
使用 linux 'strace' 我得到了更多线索:
似乎在调用 async_read_until 之后,使用 fcntl 调用的 asio 会导致我的输出文件描述符改变行为?
一段时间后它会退出打印输出:
select(4, [0 3], [], [], {300, 0}) = 1 (in [0], left {298, 830000})
readv(0, [{"\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 0\0\0\0\0\0\0\0\0\0\0"..., 512}], 1) = 1
write(2, "这是一个长句子的测试"..., 93) = 93
write(2, "这是一个长句子的测试"..., 93) = 93
... 大约 40 次
write(2, "这是一个长句子的测试"..., 93) = 53
write(2, "This is a test of a long sentence"..., 93) = -1 EAGAIN (资源暂时不可用)
write(2, "This is a test of a long sentence"..., 93) = -1 EAGAIN (资源暂时不可用)
write(2, "This is a test of a long sentence"..., 93) = -1 EAGAIN (资源暂时不可用)
write(2, "This is a test of a long sentence"..., 93) = -1 EAGAIN (资源暂时不可用)
write(2, "This is a test of a long sentence"..., 93) = -1 EAGAIN (资源暂时不可用)
...其余的,直到达到 100。
所以你可以看到选择循环等待我的输入返回键。然后我们称我为空
读取处理程序并退出 ioService。此时我调用了我的 printLines 函数并尝试打印 100 行,但在打印 40 行后退出。
这个 EAGAIN 导致输出停止写入。
再次,如果我不调用 async_read_直到我的 printf 没有损坏。
我想我知道发生了什么,当我在标准输入文件描述符上请求异步读取模式时,似乎 Asio 正在将我的标准输出文件描述符转换为异步非阻塞模式。这就是为什么在一些输出之后我在写入时收到 EAGAIN 错误。当然 printf 会忽略那些,所以我的输出被截断了。不知道这是 Asio 的 bug 还是 linux 的副作用?
这是我复制问题的简单程序:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::asio;
using namespace std;
io_service ioService;
boost::asio::streambuf inStream;
posix::stream_descriptor input(ioService, STDIN_FILENO);
void printLines()
{
for (int i = 0; i < 100; i++) {
fprintf(stderr, "This is a test of a long sentence, there will be %d more sentences after this on is printed.\n", i);
}
fflush(stderr);
}
void readHandler(const boost::system::error_code& error)
{ // Don't care about read!! }
int main()
{
boost::system::error_code ec;
//printLines(); << this works if uncommented
//ioService.post(printLines); << this works if uncommented
boost::asio::async_read_until(input, inStream, "\n",
bind(readHandler, placeholders::error)); // causes truncated output
cout << "Hit Return to continue..." << endl;
ioService.run_one( ec );
assert(!ec);
printLines(); // partial output if async_read_until is called?
return 0;
}
【问题讨论】:
-
你关于非阻塞标准错误的理论是合理的。您是否在 strace 输出中看到对描述符 2 的 fcntl 或 ioctl 调用?我在 RHEL 6 系统上运行了您的复制器,我没有看到 EAGAIN,但我确实看到了大约 60 行之后的截断输出。我确实注意到将 fprintf 更改为 std::cerr 时,问题消失了。
标签: c++ boost boost-asio