-
Notifications
You must be signed in to change notification settings - Fork 5
so5extra 1.5 Asio OneThread Dispatcher
The purpose of asio_one_thread
dispatcher is to provide a possibility to handle IO-events from Asio and SO-events from SObjectizer on the context of the Asio's io_context
. It means that SObjectizer-agents can perform IO-operations during ordinary processing of SObjectizer-messages. For example:
class request_sender : public so_5::agent_t
{
asio::io_context & io_ctx_;
public:
request_sender(context_t ctx, asio::io_context & io_svc)
: so_5::agent_t(std::move(ctx)), io_ctx_(io_svc)
{...}
...
private:
void on_perform_request(mhood_t<perform_request> req)
{
using asio::ip::tcp;
tcp::socket s(io_ctx_);
tcp::resolver resolver(io_ctx_);
asio::connect(s, resolver.resolve(req->host(), req->port()));
asio::write(s, asio::buffer(req->payload()));
std::array<char, 1024> reply_buf;
const auto n = asio::read(s, asio::buffer(reply_buf));
so_5::send<request_result>(req->reply_to(), reply_buf.data(), n);
}
};
An instance of asio_one_thread
dispatcher starts one worker thread and calls asio::io_context::run()
on it. Then the dispatcher dispatches event handlers of all agents bound to the dispatcher via asio::post()
. It means that Asio's io_context
handles the agent's events just like any other Asio's events (like results of async IO-operations).
The asio_one_thread
closes and joins this worker thread when the dispatcher is no more used (as well as result of SObjectizer Environment's shutdown).
A header file so_5_extra/disp/asio_one_thread/pub.hpp
must be included. The main SObjectizer's header file so_5/pub.hpp
can also be necessary:
// Definition of asio_one_thread dispatcher.
#include <so_5_extra/disp/asio_one_thread/pub.hpp>
// Main SObjectizer header.
#include <so_5/pub.hpp>
Then disp_params_t
instance must be prepared. For example:
namespace asio_disp = so_5::extra::disp::asio_one_thread;
asio_disp::disp_params_t params;
// Dispatcher must use its own io_context object.
params.use_own_io_context();
Then an instance of dispatcher must be created:
auto disp = asio_disp::make_dispatcher(
// SObjectizer Environment to work in.
env,
// Name for data source.
"my_asio_disp",
// Parameters for new dispatcher.
std::move(params) );
Then binders for agents can be obtained via dispatcher_handle_t::binder()
method:
env.introduce_coop([&](so_5::coop_t & coop) {
// Create agent and add it to the dispatcher.
coop.make_agent_with_binder<request_sender>(
disp.binder(),
disp.io_context());
});
Unlike asio_thread_pool
dispatcher there is no need to specify a strand object for agents bound to asio_one_thread
dispatcher. It's because those agents will be invoked on the context of just one worker thread.
asio_one_thread
can use its own copy of Asio's io_context
. This must be specified by disp_params_t::use_own_io_context
method:
so_5::extra::disp::asio_one_thread::disp_params_t params;
params.use_own_io_context(); // New instance of io_context will be created dynamically here.
This io_context
instance will be destroyed with the instance of asio_one_thread
dispatcher.
But asio_one_thread
can also use an io_context
created by someone else. For example:
int main()
{
// An io_context which will live to the end of the whole application.
asio::io_context io_svc;
...
// Start of SObjectizer Environment.
so_5::launch([&](so_5::environment_t & env) {
// Create an asio_thread_pool dispatcher.
so_5::extra::disp::asio_one_thread::disp_params params;
params.use_external_io_context(io_svc);
auto disp = so_5::extra::disp::asio_one_thread::make_dispatcher(
env, "my_asio_disp", std::move(params));
...
});
...
}
In such case asio_one_thread
won't control lifetime of io_context
instance. But asio_one_thread
will call io_context::run()
and io_context::stop()
methods.
asio_one_thread
is implemented by template-classes which behaviour is controlled by specific traits. By default default_traits_t
is used as traits type. It means that a call:
auto disp = so_5::extra::disp::asio_one_thread::make_dispatcher(...);
is equivalent to that call:
auto disp = so_5::extra::disp::asio_one_thread::make_dispatcher<
so_5::extra::disp::asio_one_thread::default_traits_t>(...);
The type so_5::extra::disp::asio_one_thread::default_traits_t
is empty at the moment. It wasn't empty in so5extra-1.4, but its content was removed during the development of v.1.5.0. Because default_traits_t
is empty and the implementation of asio_one_thread dispatcher doesn't take anything from it, there is no sense to specify a custom traits type (at the current moment).
Despite the fact that the type so_5::extra::disp::asio_one_thread::default_traits_t
it empty it is kept here to have a possibility to extend it in future versions.
If a user wants to use custom thread type with asio_one_thread dispatcher then he/she has to use the standard SObjectizer's mechanism with abstract_work_thread_t
/abstract_work_thread_factory_t
interfaces. That mechanism was introduced in SObjectizer-5.7.3 and so5exta-1.5 utilizes it.