This works well:
class cStartSequence
{
void Tick()
{
// do something
}
void Wait()
{
myTimer->expires_from_now(
boost::posix_time::seconds( mySecs ) );
myTimer->async_wait(boost::bind(
&cStartSequence::Tick,
this
));
}
...
};
I want to be able to cancel the timer and have the handler do something different
void Tick( boost::system::error_code & ec )
{
if( ! ec )
// do something
else
// do something different
}
The question is how to modify the call to async_wait?
This does not compile
myTimer->async_wait(boost::bind(
&cStartSequence::Tick,
this,
boost::asio::placeholders::error
));
compiler complaint:
C:\Users\James\code\boost\v1_63\boost\bind\bind.hpp|319|error:
no match for call to
'(boost::_mfi::mf1<void, pinmed::wrs::cStartSequence, boost::system::error_code&>)
(pinmed::wrs::cStartSequence*&, const boost::system::error_code&)'
I tried some variations on the async_wait parameters, but no luck.
boost:asio v1.63, windows 10, code::blocks v16.01
Your Tick method takes a non-const reference. That's not ok (and doesn't satisfy the handler requirements). Use either
void Tick(boost::system::error_code const& ec);
Or maybe
void Tick(boost::system::error_code ec);
The first one is preferred by Asio author(s) for slightly obscurantist reasons (library-specific optimizations IIRC)
PS. For safe cancellation of deadline timers see also
cancel a deadline_timer, callback triggered anyway
Proper cleanup with a suspended coroutine
Related
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.
}
}
I want to use std::functions for callback parameters in a wrapper class.
The class wraps a library that allows asynchronous TCP/IP operations (actually boost::asio but neither boost::asio nor TCP/IP should matter here, only that it has asynchronous operations).
The library functions allow me to pass another callback function object that is asynchronously called when the requested operation is finished.
Depending on the result of the asynchronous operation I want to invoke the callback specified by my client or start further operations.
The following code tries to sketch what I intend.
using ConnectHandler = std::function<void(boost::system::error_code ec)>;
class MyConnection
{
public:
void Connect(ConnectHandler handler); // (1)
}
void MyConnection::Connect(ConnectHandler handler)
{
SomeLibrary::async_connect(...,
[handler](boost::system::error_code ec, ...) // (2)
{
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
});
}
The client code would look something like this
MyConnection conn;
conn.Connect([](boost::system::error_code ec)
{
//check ec and start read/write operation
});
My question is:
what is the best way to declare my Connect method in (1), f.e
void Connect(ConnectHandler handler);
void Connect(const ConnectHandler& handler);
void Connect(ConnectHandler&& handler);
and depending on that how do I correctly capture the callback handler in the lambda capture clause in (2) such that I can call it in (3)?
A side note:
the clients instance of MyConnection will never go out of scope until all asynchronous operations have completed!
std::function are cheap to move, so taking it by value is acceptable. Taking by && is mostly pointless, as at best is saves a move. And it forces the caller to move, not copy, and maybe the caller wants to copy?
They are not cheap to copy, so you could consider capturing by move in your callable object.
In C++14, this is as simple as:
[handler=std::move(handler)]
as a capture list (generalized capture expressions).
In C++11 you need to write a custom object to do this.
struct custom_work {
ConnectHandler handler;
void operator()(boost::system::error_code ec, ...) const {
//Depending on ec start a nested read/write operation.
//One way or another it finally invokes the callback
handler(ec); // (3)
}
};
then
SomeLibrary::async_connect(...,
some_work{std::move(handler)}
);
which has the disadvantage of moving the code from inline to out of line.
I've got some trouble with the asio timer.
It is bind to a class method, and when I reload the timer (each time I'm waiting for data or ack), the call back method is called (according to the boost spec).
The problem is that I don't know how to differentiate the cancelation or the completion of the timer.
How should I do that ?
Thanks !
const int TIMER_DURATION = 5000; // ms
tftp_connection::tftp_connection (std::string id,
std::string file_name,
connection_type_enum connection_type,
tftp_server* server,
boost::asio::io_service& io_service)
: timer(io_service, boost::posix_time::milliseconds(TIMER_DURATION)) {
//...
// when sending a block and waiting for acknowledgement
timer.expires_from_now(boost::posix_time::milliseconds(TIMER_DURATION));
timer.async_wait(boost::bind(&tftp_connection::timeout_callback , this));
//...
void tftp_connection::timeout_callback() {
std::cout << "Time Out\n"; }
Looks like you want to check the error code that can be given to the callback if you use the right callback function type. Have a look at:
Boost async_wait example
Your callback should look somehow like this:
void tftp_connection::timeout_callback(const boost::system::error_code& e) {
if(e.value() == ERROR_TIMEOUT) // Or whatever error code you want to check for.
{
std::cout << "Time Out\n";
}
}
in addition, you need to change the bind to:
timer.async_wait(boost::bind(&tftp_connection::timeout_callback , this,boost::asio::placeholders::error));
The boost::asio::placeholders::error tells the bind to create a function which can use the error code as an argument.
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
{
}
}
suppose i have class X which encapsulates asio::ip::tcp::socket and deadline_timer. timer is used to break the connection if it is being too slow. Here is X:
class X
{
public:
typedef boost::function<void(const error_code&)> Handler;
void f(Handler);
void close();
private:
void on_connected(const error_code&);
void on_timeout(const error_code&);
void on_work_is_done(const error_code&);
Handler h_;
socket s_;
deadline_timer t_;
};
The function f does some work (send, receive, ...) and then calls handler like this:
void on_work_is_done(const error_code& e)
{
//swapping handlers to release handler after function exits
Handler h;
h.swap(h_);
h(e);
}
During that time the timer t is ticking. So my problem is:
what is a good way to make X::close? close() must close socket s and stop timer t, and it seems very natural that it must call handler h but only after all async operations (on s and t) are cancelled. If there wasn't timer, then the problem is solved:
void X::close() { s.close(); }
the async operations will be cancelled and on_work_is_done() will be called with err == operation_aborted, this will be passed to handler and then the handler will be released. Everything is ok. But since there are 2 objects and each of them might have some pending async operations, the problem appears to be more complex. Because if we do
void X::close()
{
s.close();
t.cancel();
}
both handlers (on_work_is_done, on_timeout) will be invoked, but we may call swapped handler_(err) from the handler that was invoked last.
Is there some straightforward solution?
I see the following approaches:
a) add size_t counter_ which will be set to 2 in X::close() and each of handlers will decrease it by 1. So the handler that made counter_ == 0 will invoke handler_(operation_aborted);
b) run t.cancel() and from on_timeout(err) if err == operation_aborted call s.cancel and from on_work_is_done() invoke handler_(operation_aborted)
Or the whole approach is bad and there is a better way?