Boost ASIO,未调用async_read_some回调

时间:2016-03-03 22:43:31

标签: c++ boost boost-asio

我的代码适用于read_some,但不适用于async_read_some。我正在阅读的数据是5个字符长,而MAX_RESPONSE_SIZE 256。打开端口后,我从主电话拨打async_read_some一次,但在我刷了几次我的接口卡后再也没有调用回叫。我尝试在io_service.run()之后添加async_read_some,但它没有帮助。我错过了什么吗?谢谢。

标题

boost::system::error_code error;
boost::asio::io_service io_service;
typedef boost::shared_ptr<boost::asio::serial_port> serial_port_ptr;
serial_port_ptr serial_port;
char read_buffer[MAX_RESPONSE_SIZE];

打开

serial_port.reset();
serial_port = serial_port_ptr(new boost::asio::serial_port(io_service));
serial_port->open(device_path, error);

serial_port->set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
serial_port->set_option(boost::asio::serial_port_base::character_size(8));
serial_port->set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
serial_port->set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
serial_port->set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));

boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));

serial_port->async_read_some(
            boost::asio::buffer(read_buffer, MAX_RESPONSE_SIZE),
            boost::bind(
                &serial_comm::data_received,
                this, boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        );

回调

void serial_comm::data_received(const boost::system::error_code& error, size_t bytes_transferred)
{
    // do stuff
}

2 个答案:

答案 0 :(得分:2)

您必须确保始终有工作要做,以便io_service :: run()不会返回并完成正在运行的线程。

如评论中所述,您可以创建一个io_service :: work。但是,我认为这是人为的,是设计问题的症状。

更好的答案可能是,在data_received处理程序中,如果没有发生致命错误,您应准备下一次读取

void serial_comm::data_received(
  const boost::system::error_code& error,
  size_t bytes_transferred)
{
    // do stuff

   if( any_kind_of_fatal_error )
   {
       // return without setting up the next read
       // this will end reading
      return;
   }

   // the last read was successful
   // so setup for the next
   serial_port->async_read_some(
        boost::asio::buffer(read_buffer, MAX_RESPONSE_SIZE),
        boost::bind(
            &serial_comm::data_received,
            this, boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
        )
    );

}

答案 1 :(得分:1)

基本上我的问题是在同一个函数中io_service之后没有启动async_read_some线程。你能怪我吗?这个东西不是很清楚。这是我的代码,万一有人想要它(INFO和ERROR来自boost记录,请参阅我的其他问题):

<强> serial_comm.hpp

#ifndef __SERIAL_COMM_HPP
#define __SERIAL_COMM_HPP

#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

#include <string>
#include <atomic>

#include "logging.hpp"  // Boost logging

#define MAX_RESPONSE_SIZE 256

class serial_comm
{
    public:
        void open_serial_port (std::string device_path, unsigned int baud_rate);
        void close_serial_port (void);
        void async_read_some (void);

        std::string serial_read_data;
        std::atomic <bool> serial_data_read_complete{false};
    private:
        // functions
        void data_received (const boost::system::error_code& ec, size_t bytes_transferred);

        // variables
        boost::mutex mutex;
        boost::system::error_code error;
        boost::asio::io_service io_service;
        typedef boost::shared_ptr<boost::asio::serial_port> serial_port_ptr;
        serial_port_ptr serial_port;
        char read_buffer[MAX_RESPONSE_SIZE];
};

#endif  // __SERIAL_COMM_HPP

<强> serial_comm.cpp

#include "../include/serial_comm.hpp"

void serial_comm::open_serial_port (std::string device_path, unsigned int baud_rate)
{   
    INFO << "started";

    try
    {
        serial_port.reset();
        serial_port = serial_port_ptr(new boost::asio::serial_port(io_service));
        serial_port->open(device_path, error);
        if (error) 
        {
            ERROR << "error.message() >> " << error.message().c_str();
            throw -3;
        }
        // set options
        serial_port->set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
        serial_port->set_option(boost::asio::serial_port_base::character_size(8));
        serial_port->set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
        serial_port->set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
        serial_port->set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));    

    }
    catch (int error)
    {
        ERROR << "error = " << error;
        throw -1;
    }
    catch (const std::exception &e)
    {
        ERROR << "e.what() = " << e.what();
        throw -2;
    }

    INFO << device_path << " opened correctly";     
    INFO << "ended";

    return;
}

void serial_comm::close_serial_port()
{
    boost::mutex::scoped_lock lock(mutex);  // prevent multiple thread access

    INFO << "started";

    try
    {
        if (serial_port)
        {
            serial_port->cancel();
            serial_port->close();
            serial_port.reset();
        }
        else 
        {
            WARNING << "serial port is not open";
        }
        io_service.stop();
        io_service.reset();
    }
    catch (const std::exception &e)
    {
        ERROR << "e.what() = " << e.what();
        throw -1;
    }

    INFO << "ended";

    return;
}

void serial_comm::async_read_some (void)
{
    boost::mutex::scoped_lock lock (mutex); // prevent multiple threads

    INFO << "started";

    std::string data;

    try
    {
        if (serial_port.get() == NULL || !serial_port->is_open())
        {
            WARNING << "serial port is not open";
            throw -2;
        }

        serial_port->async_read_some(
            boost::asio::buffer(read_buffer, MAX_RESPONSE_SIZE),
            boost::bind(
                &serial_comm::data_received,
                this, boost::asio::placeholders::error, 
                boost::asio::placeholders::bytes_transferred
            )
        );
        // start io_service run thread after giving it work
        boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
    }
    catch (const std::exception &e)
    {
        ERROR << "e.what() = " << e.what();
        throw -1;
    }

    INFO << "ended";

    return;
}

void serial_comm::data_received(const boost::system::error_code& error, size_t bytes_transferred)
{
    boost::mutex::scoped_lock lock(mutex);  // prevent multiple thread access

    INFO << "started";

    try
    {
        if (serial_port.get() == NULL || !serial_port->is_open())
        {
            WARNING << "serial port is not open";
            throw -2;
        }
        if (error) 
        {
            ERROR << "error.message() >> " << error.message().c_str();
            throw -3;
        }           
        for (unsigned int i = 0; i < bytes_transferred; ++i) {
            serial_read_data += read_buffer[i];
        }       
        INFO << "bytes_transferred = " << bytes_transferred << "; serial_read_data = " << serial_read_data; 
        serial_data_read_complete = true;
    }
    catch (const std::exception &e)
    {
        ERROR << "e.what() = " << e.what();
        throw -1;
    }

    // prevent io_service from returning due to lack of work    
    serial_port->async_read_some(
        boost::asio::buffer(read_buffer, MAX_RESPONSE_SIZE),
        boost::bind(
            &serial_comm::data_received,
            this, boost::asio::placeholders::error, 
            boost::asio::placeholders::bytes_transferred
        )
    );

    INFO << "ended";

    return;
}

<强>的main.cpp

#include "../include/serial_comm.hpp"

int main(void) 
{
    serial_comm _serial_comm;

    try
    {       
        _serial_comm.open_serial_port("/dev/ttyS0", 9600);
        _serial_comm.async_read_some(); // this function will always check for data
        loop:       
        while (!_serial_comm.serial_data_read_complete)
        {
            sleep(1);
        }
        INFO << "_serial_comm.serial_read_data = " << _serial_comm.serial_read_data;
        _serial_comm.serial_read_data.clear();
        _serial_comm.serial_data_read_complete = false;
        goto loop;      
    }
    catch (int error)
    {
        ERROR << "error >> " << error;
        return;
    }

    FATAL << "main ended";

    return;
}