Reputation: 624
I'm trying to implement my own boost::asio
operation, executed asynchronously during io_context.run()
.
Also I need to implement a cancellable operation which waits for some condition / predicate is met (or boost::signals2::signal
is called) - and next, calls any completion handler in io_context
thread? Is such functionality already available in Boost?
My code is inspired by Boost documentation:
#include <boost/asio.hpp>
#include <iostream>
/// From boost documentation:
/// — If the initiating function is not a member function,
/// the associated executor is that returned by the get_executor member function
/// of the first argument to the initiating function.
struct executor_owner
{
using executor_type = boost::asio::io_context;
executor_type* m_executor = nullptr;
explicit executor_owner(executor_type& ex)
: m_executor(&ex)
{
}
executor_type& get_executor() BOOST_ASIO_NOEXCEPT
{
std::cout << "get_executor() called." << std::endl;
return *m_executor;
}
};
/// My initiating function
template<class CompletionToken>
auto async_xyz(executor_owner executorOwner, CompletionToken&& token)
{
using completion_handler_t = typename boost::asio::async_completion<CompletionToken, void(executor_owner&)>::completion_handler_type;
return boost::asio::async_initiate<CompletionToken, void(executor_owner&)>(
[](completion_handler_t completion_handler, executor_owner& owner) {
// initiate the operation and cause completion_handler to be invoked
// with the result
std::cout << "I'm performing the async func operation here!" << std::endl;
completion_handler();
},
token, executorOwner);
}
int main()
{
boost::asio::io_context io_context;
executor_owner executorOwner(io_context);
async_xyz(executorOwner, []()
{
std::cout << "completion handler here!" << std::endl;
});
// I expect that completion handler will be called asynchronously, during io_context::run().
// Unfortunately, completion handler has already been called.
// std::cout << "io_context begin." << std::endl;
// io_context.run(); // It doesn't matter. completion handler
// std::cout << "io_context done." << std::endl;
return 0;
}
// Output:
// I'm performing the async func operation here!
// completion handler here!
My questions:
boost::asio
design?get_executor()
method as described in boost documentation?boost::asio::async_initiate
internally posts operation to io_context
, or have I call io_context::post(...)
manually in my custom operation implementation (to trigger the completion handler)?I'm using boost 1.82 and C++14 (but C++11 solution is preferred).
All hints welcome, regards. And in case of down vote, please explain what's wrong.
Upvotes: 0
Views: 1042
Reputation: 393769
A few notes
/// From boost documentation: /// — If the initiating function is not a member function, /// the associated executor is that returned by the get_executor member function /// of the first argument to the initiating function.
The first argument to the initiating function is completion_handler_t
. If you need to bind an executor to it, simply use bind_executor
. (The other common method is implementing a hand-coded initiation function object that has the associated executor).
// initiate the operation and cause completion_handler to be invoked // with the result
You should dispatch/post it to "cause [it] to be invoked":
asio::dispatch(completion_handler);
Thus, everything simplifies to:
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
/// My initiating function
template <typename CompletionToken> auto async_xyz(CompletionToken&& token) {
return asio::async_initiate<CompletionToken, void()>(
[](auto completion_handler) {
// initiate the operation and cause completion_handler to be invoked
// with the result
std::cout << "I'm performing the async func initiation here!" << std::endl;
asio::dispatch(completion_handler);
},
token);
}
int main() {
asio::io_context io_context;
auto f = [] { std::cout << "completion handler here!" << std::endl; };
async_xyz(bind_executor(io_context.get_executor(), f));
std::cout << "io_context begin." << std::endl;
io_context.run();
std::cout << "io_context done." << std::endl;
}
Printing the expected
I'm performing the async func initiation here!
io_context begin.
completion handler here!
io_context done.
Upvotes: 1