使用async_read_until时boost :: asio是否会截断输出?

时间:2011-04-08 23:01:01

标签: c++ boost boost-asio

这个让我难过

如果我使用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;
}

1 个答案:

答案 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开发版本,看看行为是否已经改变。