C++ Boost ASIO,异步读取一些未调用的回调

C++ Boost ASIO,异步读取一些未调用的回调,c++,boost,boost-asio,C++,Boost,Boost Asio,我的代码适用于读取部分,但不适用于异步读取部分。我正在读取的数据长度为5个字符,而MAX\u RESPONSE\u SIZE 256。打开端口后,我从main调用了一次async\u read\u some,但在我刷了几次prox卡之后,就再也没有调用过回调。我尝试在async\u read\u some之后添加io\u service.run(),但没有效果。我错过什么了吗?多谢各位 标题 boost::system::error_code error; boost::asio::io_ser

我的代码适用于
读取部分
,但不适用于
异步读取部分
。我正在读取的数据长度为5个字符,而
MAX\u RESPONSE\u SIZE 256
。打开端口后,我从main调用了一次
async\u read\u some
,但在我刷了几次prox卡之后,就再也没有调用过回调。我尝试在
async\u read\u some
之后添加
io\u service.run()
,但没有效果。我错过什么了吗?多谢各位

标题

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->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
}

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

如注释中所述,您可以创建io_服务::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
        )
    );

}

基本上,我的问题是在同一个函数中的
async\u read\u some
之后没有启动
io\u服务
线程。你能怪我吗?这东西不是很清楚。以下是我的代码,以防有人需要(信息和错误来自boost日志,请参阅我的其他问题之一):

串行通信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
#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;
}
#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;
}
\ifndef\uuu串行通信\uu水电站
#定义串行通信HPP
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括“logging.hpp”//Boost日志
#定义最大响应大小256
类串行通信
{
公众:
无效开放串行端口(标准::字符串设备路径,无符号整数波特率);
无效关闭串行端口(无效);
void async\u read\u some(void);
std::字符串串行读取数据;
原子串行数据读取完成{false};
私人:
//功能
接收到无效数据(常量boost::系统::错误代码和ec,大小\u t字节\u传输);
//变数
互斥互斥;
boost::system::error\u code error;
boost::asio::io_服务io_服务;
typedef boost::共享的\u ptr串行\u端口\u ptr;
串行端口ptr串行端口;
字符读取缓冲区[最大响应大小];
};
#endif/\串行通信\水电站
串行通信cpp

#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
#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;
}
#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;
}
#包括“./包括/串行通信hpp”
无效串行通信::打开串行端口(标准::字符串设备路径,无符号整数波特率)
{   
信息打开(设备路径,错误);
如果(错误)
{
错误设置_选项(boost::asio::serial_port_base::character_size(8));
串行_端口->设置_选项(boost::asio::串行_端口_基::停止_位(boost::asio::串行_端口_基::停止_位::一));
串行_端口->设置_选项(boost::asio::串行_端口_基::奇偶校验(boost::asio::串行_端口_基::奇偶校验::无));
串行端口->设置选项(boost::asio::串行端口\基础::流量\控制(boost::asio::串行端口\基础::流量\控制::无));
}
捕获(整数错误)
{

错误我们需要查看调用
async\u read\u some
的整个代码流,从
io\u服务调度的位置开始,到返回的位置结束,允许线程执行其他工作。很可能,调用
run
的线程正在执行其他操作,因此无法处理完成。(您可以通过使用调试器停止程序并查看该线程正在执行的操作进行检查。)我调用open,然后从
int main
读取;没有其他内容。boost线程不是运行
io_服务吗?
io_服务。run()
可能会立即返回,因为没有工作。通常的做法是创建
io\u服务::work
并将其附加到
io\u服务
,以防止
运行()
返回。由于某些原因,它可能没有返回。使用调试器找出它正在执行的操作。它可能已终止。它可能会被困在其他代码段中等待某些内容。在
boost::asio::io_服务::work work work(io_服务);
之前添加
boost::thread t(boost::bind)(&boost::asio::io_服务::运行和io_服务))
也没有帮助;
读取一些
块,直到我刷卡并有数据,然后它得到它,我需要复制它;或者只是将
读取一些
放在一个线程中谢谢,但是从未调用
接收到的数据
;我想我需要在
异步读取一些
之后启动io服务运行线程,这样它就有了两个线程rk?是的。请注意,接收到的数据将在执行run()的线程中执行。因此,为了清楚起见,我还将从该线程执行async_read_some。“基本上,我的问题是在同一个函数中async_read_some之后没有启动io_服务线程。你能怪我吗?这不是很清楚。”不,我不能怪你。文档太糟糕了。所以我来这里……但是你的评论强调了为什么我的代码不起作用,所以谢谢你!