这个让我难过!
如果我使用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之后,asio使用fcntl调用,会导致我的输出文件描述符改变行为?
它会在一段时间后退出打印输出:
select(4,[0 3],[],[],{300,0})= 1(在[0]中,左{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 \ 0 \ 0“...,512}],1)= 1
写(2,“这是对长句子的考验”......,93)= 93
写(2,“这是对长句子的考验”......,93)= 93
...大约40次
写(2,“这是对长句子的考验”......,93)= 53
写(2,“这是对长句子的测试”......,93)= -1 EAGAIN(资源暂时不可用)
写(2,“这是对长句子的测试”......,93)= -1 EAGAIN(资源暂时不可用)
写(2,“这是对长句子的测试”......,93)= -1 EAGAIN(资源暂时不可用)
写(2,“这是对长句子的测试”......,93)= -1 EAGAIN(资源暂时不可用)
写(2,“这是对长句子的测试”......,93)= -1 EAGAIN(资源暂时不可用)
......其余的一直到达100
所以你可以看到select循环等待我的输入返回键。然后我们称我为空
读取处理程序并退出ioService。这时我调用我的printLines函数并尝试打印100行,但在打印40行后退出。
此EAGAIN的某些内容导致输出停止写入
再次,如果我不调用async_read_until,我的printf不会被破坏。
我想我知道发生了什么,当我在stdin文件描述符上请求异步读取模式时,似乎Asio正在将我的stdout文件描述符转换为异步非阻塞模式。这就是为什么在输出后我在写入时出现EAGAIN错误的原因。当然printf忽略那些因此我的输出被截断。不知道这是Asio中的错误还是只是对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;
}
答案 0 :(得分:2)
如果我在ioctl
printLines
插入以下来电
int opt = 0;
ioctl( STDIN_FILENO, FIONBIO, &opt );
printLines();
预期行为
samm@macmini ~> ./a.out
Hit Return to continue...
This is a test of a long sentence, there will be 0 more sentences after this on is printed.
...
This is a test of a long sentence, there will be 96 more sentences after this on is printed.
This is a test of a long sentence, there will be 97 more sentences after this on is printed.
This is a test of a long sentence, there will be 98 more sentences after this on is printed.
This is a test of a long sentence, there will be 99 more sentences after this on is printed.
samm@macmini ~>
虽然我不清楚为什么会发生这种情况,但它可能是ioctl
的副作用,这主要是内核/设备特有的。当在各种手册页周围徘徊时,我没有看到任何描述这种行为的内容。您可以尝试使用fprintf
中的printLines
切换为使用posix::stream_descriptor
代替STDERR_FILENO
。
编辑:看起来Boost.Asio有一些recent changes可能会解决此问题。具体地
为其添加了新的non_blocking()函数 管理的非阻塞行为 套接字或描述符。该 名为io_control()的命令 non_blocking_io现已弃用 赞成这些新功能。
添加了新的native_non_blocking() 管理的功能 底层的非阻塞模式 套接字或描述符。这些功能 旨在允许 任意封装 非阻塞系统调用为 异步操作,以某种方式 对用户来说是透明的 套接字对象。功能没有 对行为的影响 套接字的同步操作 或描述符。
对我来说很有意思。我在我的Mac上使用Boost 1.45运行你的复制器,这些更改将在即将推出的Boost 1.47中。我将尝试抓住Chris最新的asio开发版本,看看行为是否已经改变。