boost :: asio为串口调用错误的处理程序

时间:2013-10-31 21:05:08

标签: c++ visual-studio-2010 serial-port boost-asio

对于嵌入式系统接口,我实现了一个具有多达8种读取模式的类(下面的代码只显示了两种--FREERUN和BLOCKRUN),用于读取串行端口。此阅读器的简化ReaderTest()函数如下所示:

void CSerialBoost::ReaderTest()
{
while (RUNflag)
    switch (RUNstate) {

    case FREERUN:
            port.async_read_some(asio::buffer(TextIn, SZTXT),
                boost::bind(&CSerialBoost::OnReadFree, this, asio::placeholders::error, asio::placeholders::bytes_transferred));

            server.reset();
            server.run(error);      // it calls OnReadBlock() here
            break;

    case BLOCKRUN:
            port.async_read_some(asio::buffer(TextIn, SZTXT),
                boost::bind(&CSerialBoost::OnReadBlock, this, asio::placeholders::error, asio::placeholders::bytes_transferred));

            server.reset();
            server.run(error);       // it calls OnReadFree() here
            break;

    default:    break;
    }

    port.cancel(error); // cancel all IO operations
}

CSerialBoost类具有以下成员:

asio::io_service    server;
asio::serial_port   port;
asio::error_code    error;

volatile int    RUNstate;   // reader mode
volatile int    RUNflag;    // start/stop flag

当我从一种模式切换到另一种模式时,会出现意外行为。 假设没有传入数据并且代码在FREERUN中运行,为了从另一个线程切换到BLOCKRUN,我做了:

RUNstate = BLOCKRUN;
server.stop();      // unblock the event loop

操作切换到BLOCKRUN,就像它应该的那样,当它到达BLOCKRUN情况下的server.run(错误)行时,它调用CSerialBoost :: OnReadFree()函数并返回错误operation_aborted。当它切换回FREERUN时会发生同样的情况 - 它在FREERUN情况下到达server.run(错误)时调用CSerialBoost :: OnReadBlock()。

这是非常误导的,因为它总是调用其他模式的功能。当我停止/取消IO服务时,我希望每个案例都可以调用它自己的函数(或者什么都没有)。 我期待太多,还是这是正常的操作?难道我做错了什么? 请提示我如何处理这个问题。 (我正在使用boost:asio 1-5-3在Win XP和Win 7下,Visual Studio 2010,我是新手来提升)

谢谢你,MA。

1 个答案:

答案 0 :(得分:0)

这是预期的行为。

io_service::stop() io_service::reset() 仅控制io_service事件循环的状态;既不会影响为延迟调用(准备运行)或用户定义的处理程序对象安排的处理程序的生命周期。

当调用server.run()时,async_read_some操作已排队到io_service。当事件循环通过server.stop()显式停止时,如果尚未调用操作的完成处理程序,则操作或完成处理程序仍在io_service中排队。然后执行继续执行while循环,其中port.cancel()强制取消port上的未完成操作,将其完成处理程序设置为准备运行,错误代码为{{1 }}。因此,下次调用boost::asio::error::operation_aborted时,将执行已取消操作的准备运行处理程序。

考虑:

  • 运行server.run()完成。这通常需要设置状态,取消未完成的操作,并阻止完成处理程序将其他工作发布到io_service。 Boost.Asio提供了一个正式的timeout示例,并且还显示了运行到io_service完成的超时方法here
  • 让异步调用链实现状态机。这样就无需io_servicestop()和重新reset() run()
  • 控制io_service对象的生命周期,因为io_service的{​​{3}}将导致所有未处理的处理程序被销毁一种方法可以在destructor回答中找到。< / LI>