so_4: Версия 4.4.0. Управление ACE-реакторами

Введение

В версии 4.4.0-beta5 была полностью переписана транспортная подсистема SObjectizer (подробнее см. so_4: Версия 4.4.0. Новая транспортная подсистема и so_4: Версия 4.4.0. Принцип работы коммуникационных каналов). Новые транспортные агенты теперь используют ACE-реактор для диспетчиризации и выполнения операций ввода-вывода. Но в версии 4.4.0-beta5 SObjectizer использовал реактор ACE по умолчанию (т.е. реактор, который доступен через метод ACE_Reactor::instance()). Программист мог привязать своего транспортного агента к любому другому реактору, но в этом случае программист сам должен был отвечать за создание реактора, его запуск и останов.

Начиная с версии 4.4.0-beta6 SObjectizer может работать с несколькими реакторами. Для этого в 4.4.0-beta6 добавлено понятие реестра реакторов (so_4::ace::reactor_registry_t). Реестр реакторов -- это хранилище реакторов, в котором каждому реактору задано уникальное имя. Пользователь может добавлять новые реакторы в реестр и удалять уже имеющиеся реакторы из реестра.

При старте SObjectizer Run-Time (т.е. внутри so_4::api::start()) выполняется запуск всех реакторов, зарегистрированных в реестре. При завершении работы выполняется ожидание завершения всех запущенных в начале работы реакторов. Т.о. все, что необходимо сделать пользователю -- это:

Все остальное является задачей SObjectizer.

Добавление и удаление реакторов

В реестр реакторов можно добавлять объекты, реализующие интерфейс so_4::ace::reactor_instance_t. За этим интерфейсом скрываются:

SObjectizer предоставляет несколько реализаций so_4::ace::reactor_instance_t для некоторых типов реакторов. Программист может создавать собственные реализации so_4::ace::reactor_instance_t.

Внимание:
Добавление и удаление реакторов может выполняться только до старта SObjectizer Run-Time (т.е. до вызова so_4::api::start()). Попытки добавления и удаления реакторов во время работы SObjectizer Run-Time будут игнорироваться, а соответствующие методы класса so_4::ace::reactor_registry_t будут возвращать коды ошибок.
Добавление реактора выполняется с помощью метода so_4::ace::reactor_registry_t::add():
#include <so_4/ace/h/reactors.hpp>
...
// Создание ACE_TP_Reactor-а.
so_4::ace::reactor_instance_auto_ptr_t tp_reactor =
    so_4::ace::make_tp_reactor( cfg.m_reactor_thread_count );

// Регистрация созданного реактора под именем main_reactor.
so_4::ace::reactor_registry().add(
    "main_reactor",
    tp_reactor );

Удаление реактора из реестра выполняется с помощью метода so_4::ace::reactor_registry_t::remove():

so_4::ace::reactor_registry().remove( "main_reactor" );

Внимание:
Следует осторожно подходить к удалению реакторов из реестра. SObjectizer не может проконтролировать, привязаны ли к удаляемому реактору какие-нибудь транспортные агенты или нет. Если такие агенты есть, то удаление реактора приведет к появлению в этих агентах повисших указателей на удаленного реактора. Что черевато, в лучшем случае, крахом приложения.

Привязывание транспортных агентов к реакторам

Для привязки транспортных агентов к реакторам необходимо:

Например:

// Создаем TP-реактор, который будет использоваться
// серверным сокетом.
so_4::ace::reactor_registry().add(
    "a_channel_reactor",
    // ТР-реактор будет работать на четырех нитях.
    so_4::ace::make_tp_reactor( 4 ) );

// Создаем канал и указываем, какой реактор для него будет
// использован.
so_4::rt::comm::a_sop_incoming_channel_processor_t a_channel(
  "a_channel",
  // Для задания реактора нужно использовать функцию
  // create_acceptor_controller со всеми параметрами.
  so_4::transport_layer::socket::create_acceptor_controller(
      so_4::transport_layer::socket::acceptor_params( ip_address ),
      so_4::transport_layer::channel_params_t(),
      so_4::transport_layer::socket::option_setter_auto_ptr_t(),
      // Вот и реактор, на котором предстоит работать каналу.
      so_4::ace::reactor_registry().find( "a_channel_reactor" ) ) );

Если реактор для транспортного агента не задан, то транспортный агент будет работать на реакторе по умолчанию.

Реактор по умолчанию

По умолчанию SObjectizer создает реактор, который имеет имя so_4::ace::default_reactor_name() и регистрирует его в реестре. Именно этот реактор будет использован для тех транспортных агентов, которые не привязаны к собственным реакторам.

Реактор по умолчанию создается SObjectizer при первом обращении к реестру реакторов. Поэтому программисту не нужно заботиться о его создании.

В качестве реактора по умолчанию используется ACE_Select_Reactor, работающий на одной нити.

Реактор по умолчанию может быть заменен на реактор, который больше устраивает пользователя. Для этого сначала нужно удалить реактор по умолчанию, а затем зарегистрировать в реестре новый реактор с тем же именем:

// Заменяем реактор по умолчанию на TP_Reactor.
so_4::ace::reactor_instance_auto_ptr_t tp_reactor =
    so_4::ace::make_tp_reactor( cfg.m_reactor_thread_count );

so_4::ace::reactor_registry().remove(
    so_4::ace::default_reactor_name() );
so_4::ace::reactor_registry().add(
    so_4::ace::default_reactor_name(),
    tp_reactor );

Внимание:
Нельзя заменять реактор по умолчанию, если уже есть транспортные агенты, которые явно или неявно к нему привязаны. Такая замена, в лучшем случае, приведет к краху приложения.

Создание собственных реакторов

Для создания собственного реактора необходимо реализовать интерфейс so_4::ace::reactor_instance_t. Для чего можно воспользоваться шаблонными классами so_4::ace::reactor_task_t и so_4::ace::reactor_instance_template_t (на основе которых в SObjectizer реализованы Select- и ThreadPool-реакторы).

Документация по SObjectizer v.4.4 'Тебуломста'. Последние изменения: Thu Sep 18 10:26:48 2008. Создано системой  doxygen1.5.6 Intervale SourceForge.net Logo