Boost ASIO,未调用 async_read_some 回调
Posted
技术标签:
【中文标题】Boost ASIO,未调用 async_read_some 回调【英文标题】:Boost ASIO, async_read_some callback not called 【发布时间】:2016-03-03 22:43:31 【问题描述】:我的代码适用于read_some
,但不适用于async_read_some
。我正在读取的数据是 5 个字符长,而 MAX_RESPONSE_SIZE 256
.打开端口后,我从我的主服务器上调用了一次async_read_some
,但在我刷了几次代理卡后,从未调用过回调。我尝试在async_read_some
之后添加io_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.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
【问题讨论】:
我们需要查看调用async_read_some
的整个代码流,从io_service
调度它的地方开始,到它返回的地方结束,允许线程做其他工作。很可能,调用run
的线程正在执行其他操作,因此无法处理完成。 (您可以通过使用调试器停止程序并查看该线程在做什么来检查。)
我调用open,然后从int main
读取;没有别的了。 boost线程不运行io_service
吗?
您的io_service.run()
可能会立即返回,因为没有工作。通常的做法是创建一个io_service::work
并将其附加到io_service
,以防止run()
返回。
@xinthose 可能由于某种原因它不是。使用调试器找出它在做什么。它本可以终止。它可能会卡在等待其他代码中的某些内容。
在boost::asio::io_service::work work (io_service);
之前添加boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
也无济于事; read_some
阻塞,直到我刷卡并且有数据,然后它得到它,我需要复制它;或者只是将read_some
放在一个线程中
【参考方案1】:
您必须确保始终有工作要做,以便 io_service::run() 不会返回并完成正在运行的线程。
如 cmets 中所述,您可以创建一个 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
)
);
【讨论】:
谢谢,但永远不会调用data_received
;我想我需要在async_read_some
之后启动 io_service 运行线程才能正常工作?
是的。请注意,data_received 将在执行 run() 的线程中执行。因此,为了清楚起见,我也会从该线程执行 async_read_some。【参考方案2】:
基本上我的问题是在同一函数中async_read_some
之后没有启动io_service
线程。你能怪我吗?这东西不是很清楚。这是我的代码,以防有人需要(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_completefalse;
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;
【讨论】:
“基本上我的问题是在同一个函数中 async_read_some 之后没有启动 io_service 线程。你能怪我吗?这东西不是很清楚。”不,我不能怪你。文档令人震惊。因此我为什么在这里....但是您的评论强调了为什么我的代码不起作用,所以谢谢!以上是关于Boost ASIO,未调用 async_read_some 回调的主要内容,如果未能解决你的问题,请参考以下文章
boost::asio::async_read 不回调我的处理函数
boost::asio::async_read 无限循环,接收数据为零字节