How to make asynchronous call with timeout - c++

I want to make an asynchronous call in C++ with timeout, meaning I want to achieve sth like that.
AsynchronousCall(function, time);
if(success)
//call finished succesfully
else
//function was not finished because of timeout
EDIT : Where function is a method that takes a lot of time and I want to interrupt it when it takes too much time.
I' ve been looking for how to achieve it and I thinki boost::asio::deadline_timer is way to go. I guess calling timer.async_wait(boost::bind(&A::fun, this, args)) is what I need, but I do not know how to find if the call was success or was aborted due to timeout.
EDIT: after the answer from ForEveR my code now looks like this.
boost::asio::io_service service;
boost::asio::deadline_timer timer(service);
timer.expires_from_now(boost::posix_time::seconds(5));
timer.async_wait(boost::bind(&A::CheckTimer, this, boost::asio::placeholders::error));
boost::thread bt(&A::AsynchronousMethod, this, timer, args); //asynchronous launch
void A::CheckTimer(const boost::system::error_code& error)
{
if (error != boost::asio::error::operation_aborted)
{
cout<<"ok"<<endl;
}
// timer is cancelled.
else
{
cout<<"error"<<endl;
}
}
I wanted to pass the timer by reference and cancel it in the end of asynchronous method, but I got an error that I cannot access private member declared in class ::boost::asio::basic_io_object.
Maybe using the deadline timer is not that good idea ? I would really appreciate any help. I am passing the timer to the function, because the method that calls the asynchronous method is asynchronous itself and thus I cannot have one timer for whole class or sth like that.

You should use boost::asio::placeholders::error
timer.async_wait(boost::bind(
&A::fun, this, boost::asio::placeholders::error));
A::fun(const boost::system::error_code& error)
{
// timeout, or some other shit happens
if (error != boost::asio::error::operation_aborted)
{
}
// timer is cancelled.
else
{
}
}

Related

What values of error_code can a boost timer callback receive?

Like many asio callbacks asio timer callbacks take argument
const boost::system::error_code&
I am curios if it is documented what are possible values for that argument, since from my naive understanding of reading header documentation only one value beside success is possible.
void on_timeout(const boost::system::error_code& e)
{
if (e != boost::asio::error::operation_aborted)
{
// Timer was not cancelled, take necessary action.
}
}

Trouble implementing generic Timer Class using boost::asio::deadline_timer

Implementing a timer class on a UI application.
Basically the problem I have is that calling io.run() would block, rendering the async_wait call useless. From reading other posts I got the impression that somehow Timer, or at least the code that calls startCountdown, should be on another thread.
Below is my code. How do I manage this in a way that is considered correct in Boost?
class Timer
{
public:
Timer() : countdownTimer(io) { }
void startCountdown(int seconds)
{
countdownTimer.expires_from_now(boost::posix_time::seconds(seconds));
countdownTimer.async_wait(boost::bind(&Timer::on_timeout, this, _1));
io.run(); // this blocks
}
void on_timeout(const boost::system::error_code& e)
{
if (e != boost::asio::error::operation_aborted) {
cout << "Timer expired!";
}
}
private:
boost::asio::io_service io;
boost::asio::deadline_timer countdownTimer;
}
You shouldn't call the run member function of io_service but rahter one of :
run_one
poll
poll_one
Depending on your design goal.
Also note that boost Asio is not really designed to be a secondary library to use for some features but rather as a core element of your program, it is more a spine than an arm.
A thread dedicated to handle everything linked to the io_service could also work, but good luck synchronizing shared data between a synchronous and an asynchronous world :)

Cancel pending task callback invocation when the task owner is destructed

I am implementing something looks like a HTTP server, the design is: for a already established connection, I want to reuse it for several requests, so I start another reading task with async_read on it when a request is finished, and also start a deadline_timer. If there is no input in 60 seconds, the timer will be triggered and the connection will be destructed. The thing that annoys me is that before the invocation of the connection's destructor, the callback we set to async_read will be invoked.
So, my question is, is there any way to cancel the pending reading task, that is, destruct the connection without the callback function invoked?
If the generic description above is not clear, the detail work flow is as below(code is attached at the bottom):
cleanup() is called when a request finished;
start the timer and another reading task in cleanup();
if time is out, HandleTimeout() is called, and it calls stop();
in stop(), do the clean work, and after it, the connection instance will be destructed.
but, after step 4, the callback() function will be called, which is registered in AsyncRead(), so, is there any way to cancel the invocation of callback()?
code:
class Connection : public boost::enable_shared_from_this<Connection>,
private boost::noncopyable {
public:
typedef Connection this_type;
void cleanup() {
timer_.expires_from_now(boost::posix_time::seconds(kDefaultTimeout));
timer_.async_wait(boost::bind(&this_type::HandleTimeout,
shared_from_this(),
boost::asio::placeholders::error));
AsyncRead();
}
void AsyncRead() {
boost::asio::async_read(*socket_, in_, boost::asio::transfer_at_least(1),
boost::bind(&this_type::callback,
shared_from_this(),
boost::asio::placeholders::error));
}
void callback(const boost::system::error_code& e) {
// ...
}
void HandleTimeout(const boost::system::error_code& e) {
if(e == boost::asio::error::operation_aborted)
LDEBUG << "The timeout timer is cancelled.";
else if(e)
LERROR << "Error occurred with the timer, message: " << e.message();
else if(timer_.expires_at()
<= boost::asio::deadline_timer::traits_type::now()) {
LDEBUG << "Connection timed out, close it.";
stop();
}
}
virtual void stop() {
connected_ = false;
socket_->close();
connection_manager_.stop(shared_from_this());
}
private:
// ...
boost::asio::deadline_timer timer_;
};
There is no clean way to accomplish this. The only way to guarantee that ready-to-run handlers, such as Connection::callback(), will not be invoked is to either:
Stop processing the io_service event loop.
Destroy the io_service, as the io_service's destructor will cause all outstanding handlers to be destroyed.
In the example code, consider returning in Connection::callback() if the socket is no longer open:
void callback(const boost::system::error_code& error)
{
if (!socket_.is_open()) return;
// ...
}
Also note that the error_code argument is not enough to deduce whether the timeout has occurred. It is possible that Connection::callback() is queued for invocation with an error_code of boost::system::errc::success when socket::close() is invoked. Hence, there are no operations to cancel.

Having a hard time understanding a few concepts with Boost ASIO TCP with async_read and async_write

I'm having a hard time understand the correct way I should structure a tcp client when using async_read and async_write. The examples seem to do a async_read after connecting and then have async_write in the handler.
In the case of my client and sever, when the client connects it needs to check a queue of messages to write and check to see if anything needs to be read. One of the things I'm having a hard time with is understanding how this would work asynchronously.
What I envision is in the async_connect handler, the thread would call async_write if anything is in the sendQueue and call async_read over and over. Or should it check if anything is available to be read before it does an async_read?
Below is an example of what I'm talking about.
void BoostTCPConnection::connectHandler()
{
setRunning(true);
while (isRunning())
{
//If send Queue has messages
if ( sendSize > 0)
{
//Calls to async_write
send();
}
boost::shared_ptr<std::vector<char> > sizeBuffer(new std::vector<char>(4));
boost::asio::async_read(socket_, boost::asio::buffer(data, size), boost::bind(&BoostTCPConnection::handleReceive, shared_from_this(), boost::asio::placeholders::error, sizeBuffer));
}
}
void BoostTCPConnection::handleReceive(const boost::system::error_code& error, boost::shared_ptr<std::vector<char> > sizeBuffer)
{
if (error)
{
//Handle Error
return;
}
size_t messageSize(0);
memcpy((void*)(&messageSize),(void*)sizeBuffer.data(),4);
boost::shared_ptr<std::vector<char> > message(new std::vector<char>(messageSize) );
//Will this create a race condition with other reads?
//Should a regular read happen here
boost::asio::async_read(socket_, boost::asio::buffer(data, size),
boost::bind(&BoostTCPConnection::handleReceiveMessage, shared_from_this(),
boost::asio::placeholders::error, message));
}
void BoostTCPConnection::handleReceiveMessage(const boost::system::error_code& error, boost::shared_ptr<std::vector<char> > rcvBuffer)
{
if (error)
{
//Handle Error
return;
}
boost::shared_ptr<std::string> message(new std::string(rcvBuffer.begin(),rcvBuffer.end()));
receivedMsgs_.push_back(message);
}
void BoostTCPConnection::handleWrite(const boost::system::error_code& error,size_t bytes_transferred)
{
//Success
if (error.value() == 0)
return;
//else handleError
}
Conceptually, async_read waits for data to be received. You should call it any time you want something to happen after data is received and a read isn't already pending. Similarly, async_write waits for data to be written. You should call it any time you need to write data and a write isn't already pending.
You should call async_read when you complete the connection. Before your async_read handler returns, it should probably call async_read again.
When you need to write to the connection, you should call async_write (if a write isn't already pending). In your async_write handler, if you still need to write more, you should call async_write again.
If no read is already pending, you can call async_read in your write handler, if you wish to resume reading after you finish writing. You can also just keep a read always pending. That's up to you.
You should not check if there's anything to read before calling async_read. The point of async_read is for it to complete when there's something to read. It's a smart way of waiting and doing other things in the meantime.

Trying to use deadline_timer to add timeout to read_until

Maybe I am misunderstanding how things work, but I am trying to add a timeout to a read_until call, so I created a deadline_timer and started it before calling read_until, but the read_until still blocks everything, and the timer never gets activated. Am I doing it wrong? Below are some snippets from my code.
void MyClass::handle_timeout(const boost::system::error_code& error)
{
// Our deadline timer went off.
std::cout << "Deadline Timer was triggered." << std::endl;
Disconnect();
}
// Read some data.
void MyClass::ReadData(){
boost::asio::streambuf response;
deadline_.expires_from_now(boost::posix_time::seconds(DEFAULT_TIMEOUT));
deadline_.async_wait(boost::bind(&MyClass::handle_timeout, this, _1));
boost::asio::read_until(socket_,response,asString);
}
you're misunderstanding how things work. If you desire cancelability, you need to use the asynchronous methods such as
boost::asio::async_read_until(...);
instead of
boost::asio::read_until(socket_,response,asString);