C++ asio::read 超时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13126776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
asio::read with timeout
提问by Chris K.
I need to know how to read (sync or async doesn't matters) with a timeout. I want to check if a device is connected with a serial port or not.
我需要知道如何超时读取(同步或异步无关紧要)。我想检查设备是否与串口连接。
For that I use asio::write
and then I wait for the response of the device.
为此,我使用asio::write
然后等待设备的响应。
If a device is connected asio::read(serial, boost::asio::buffer(&r,1))
works fine but if there is no device the program stops, which is is why I need the timeout
如果设备连接asio::read(serial, boost::asio::buffer(&r,1))
工作正常但如果没有设备程序停止,这就是我需要超时的原因
I know that I need a deadline_timer
but I have no idea how to use it in the async_read
function.
我知道我需要一个,deadline_timer
但我不知道如何在async_read
函数中使用它。
An example of how it works would be really helpful.
它如何工作的一个例子将非常有帮助。
I know that there are many similar threads and I read lot of them but I can't find a solution that helps me solving my problem!
我知道有很多类似的线程,我阅读了很多,但我找不到可以帮助我解决问题的解决方案!
回答by Robert Hegner
The code posted by Igor R.did not compile for me. Here is my improved version of his code, which works perfectly. It uses lambdas to get rid of the set_result
helper function.
Igor R. 发布的代码没有为我编译。这是我对他的代码的改进版本,效果很好。它使用 lambdas 来摆脱set_result
辅助函数。
template <typename SyncReadStream, typename MutableBufferSequence>
void readWithTimeout(SyncReadStream& s, const MutableBufferSequence& buffers, const boost::asio::deadline_timer::duration_type& expiry_time)
{
boost::optional<boost::system::error_code> timer_result;
boost::asio::deadline_timer timer(s.get_io_service());
timer.expires_from_now(expiry_time);
timer.async_wait([&timer_result] (const boost::system::error_code& error) { timer_result.reset(error); });
boost::optional<boost::system::error_code> read_result;
boost::asio::async_read(s, buffers, [&read_result] (const boost::system::error_code& error, size_t) { read_result.reset(error); });
s.get_io_service().reset();
while (s.get_io_service().run_one())
{
if (read_result)
timer.cancel();
else if (timer_result)
s.cancel();
}
if (*read_result)
throw boost::system::system_error(*read_result);
}
回答by Vikas
You don't use deadline_timer
in async_read
. But you can start two async processes:
你不用deadline_timer
in async_read
。但是您可以启动两个异步进程:
- An
async_read
process on serial port. boost::asio::serial_porthas a cancelmethod that cancels all async operations on it. - A deadline timer with required timeout. In completion handler for
deadline_timer
you cancancel
the serial port. This should close theasync_read
operation and call its completion handler with an error.
async_read
串行端口上的进程。boost::asio::serial_port有一个取消方法,可以取消对它的所有异步操作。- 具有所需超时的截止时间计时器。在完成处理程序中,
deadline_timer
您可以cancel
使用串行端口。这应该关闭async_read
操作并在错误时调用其完成处理程序。
Code:
代码:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/array.hpp>
class timed_connection
{
public:
timed_connection( int timeout ) :
timer_( io_service_, boost::posix_time::seconds( timeout ) ),
serial_port_( io_service_ )
{
}
void start()
{
timer_.async_wait
(
boost::bind
(
&timed_connection::stop, this
)
);
// Connect socket
// Write to socket
// async read from serial port
boost::asio::async_read
(
serial_port_, boost::asio::buffer( buffer_ ),
boost::bind
(
&timed_connection::handle_read, this,
boost::asio::placeholders::error
)
);
io_service_.run();
}
private:
void stop()
{
serial_port_.cancel();
}
void handle_read ( const boost::system::error_code& ec)
{
if( ec )
{
// handle error
}
else
{
// do something
}
}
private:
boost::asio::io_service io_service_;
boost::asio::deadline_timer timer_;
boost::asio::serial_port serial_port_;
boost::array< char, 8192 > buffer_;
};
int main()
{
timed_connection conn( 5 );
conn.start();
return 0;
}
回答by Igor R.
Once upon a time, the library author proposed the following way to read synchronously with timeout(this example involves tcp::socket
, but you can use serial port instead):
曾几何时,库作者提出了下面这种超时同步读取的方式(本例涉及tcp::socket
,但可以改用串口):
void set_result(optional<error_code>* a, error_code b)
{
a->reset(b);
}
template <typename MutableBufferSequence>
void read_with_timeout(tcp::socket& sock,
const MutableBufferSequence& buffers)
{
optional<error_code> timer_result;
deadline_timer timer(sock.io_service());
timer.expires_from_now(seconds(1));
timer.async_wait(boost::bind(set_result, &timer_result, _1));
optional<error_code> read_result;
async_read(sock, buffers,
boost::bind(set_result, &read_result, _1));
sock.io_service().reset();
while (sock.io_service().run_one())
{
if (read_result)
timer.cancel();
else if (timer_result)
sock.cancel();
}
if (*read_result)
throw system_error(*read_result);
}
回答by TC1
There's no one or easyanswer per se, since even if you do an async read, the callback never gets called and you now have a loose thread somewhere around.
本身没有一个或简单的答案,因为即使您进行异步读取,也永远不会调用回调,并且您现在在某处有一个松散的线程。
You're right in assuming that deadline_timer
is one of the possible solutions, but it takes some fiddling and shared state. There's the blocking TCP example, but that's for async_connect
and there's a cool thing about it returning when it has nothing to do. read
won't do that, worst case scenario -- it'll crash & burn 'cause of the invalid resource. So the deadline timer
thing is one of your options, but there's actually an easier one, that goes somewhat like this:
您认为这deadline_timer
是可能的解决方案之一是正确的,但它需要一些摆弄和共享状态。有一个阻塞 TCP 的例子,但那是为了async_connect
当它无事可做时返回它有一个很酷的事情。read
不会那样做,最坏的情况——它会因为无效资源而崩溃和烧毁。所以这deadline timer
件事是你的选择之一,但实际上有一个更简单的选择,有点像这样:
boost::thread *newthread = new boost::thread(boost::bind(&::try_read));
if (!newthread->timed_join(boost::posix_time::seconds(5))) {
newthread->interrupt();
}
Basically, do the read in another thread and kill it off if it times out. You should read up on Boost.Threads.
基本上,在另一个线程中读取并在超时时将其终止。你应该阅读Boost.Threads。
If you interrupt it, make sure the resources are all closed.
如果您中断它,请确保资源全部关闭。