so_4: Версия 4.2.6. Использование динамических объектов в динамических кооперациях

В качестве примера можно предположить, что должна быть создана динамическая кооперация из трех агентов. Каждому агенту необходим объект для работы с базой данных db_connection. Объект db_connection должен быть создан динамически при создании кооперации и уничтожен после дерегистрации кооперации.

Возникают вопросы:

При этом может быть желательно сначала создать объект db_connection, попытаться установить соединение с БД и, только если это удалось, создать динамическую кооперацию.

Так же может оказаться, что некоторые из агентов должны использовать объект db_connection в своем конструкторе, а некоторые в своем деструкторе. Но SObjectizer не определяет порядка, в котором агенты будут уничтожены. Поэтому, владельцем объекта db_connection должен быть объект, время жизни которого больше, чем время жизни любого из агентов динамической кооперации. Таким агентом может являться сама динамическая кооперация.

При дерегистрации динамической кооперации SObjectizer самостоятельно уничтожает объекты-агенты и объект-кооперацию. При этом гарантируется, что агенты будут уничтожены до кооперации. Это означает, что можно попытаться сохранить объект db_connection в динамической кооперации. В SObjectizer v.4.2.6 сделать это можно двумя способами.

Простой способ

Простой способ использует понятие "объектов, время жизни которых контролируется динамической кооперацией". Т.е. с динамической кооперацией можно связать произвольное количество объектов, которые будут уничтожены в деструкторе этой кооперации. Осуществляется это путем обращения к методу so_4::rt::dyn_agent_coop_t::add_controlled_obj().

Во многих случаях вместе с кооперацией нужно будет сохранять объекты, которые нельзя сделать производными от so_4::rt::dyn_coop_controlled_obj_t. Например, тот же объект db_connection. В этом случае на помощь приходит шаблон-адаптер so_4::rt::dyn_coop_controlled_templ_t и вспомогательная шаблонная функция so_4::rt::dyn_coop_controlled():

// Функция создания динамической кооперации
// которая должна осуществлять работу с указанной
// базой данных.
// В случае ошибок порождаются исключения.
void
create_db_coop(
  // Имя кооперации.
  const std::string & coop_name,
  // Параметры подключения к БД.
  const db_connection_params_t & connection_params
) throw( std::exception )
{
  // Для очистки ресурсов при исключениях
  // используется std::auto_ptr

  // Подключение к БД.
  std::auto_ptr< db_connection_t > db_connection_ptr(
    new db_connection_t( connection_params ) );

  // Соединение с БД установлено. Создание агентов.
  std::auto_ptr< a_reader_t > a_reader_ptr(
    coop_name + "::a_reader",
    new a_reader_t( *db_connection ) );
  std::auto_ptr< a_writter_t > a_writter_ptr(
    coop_name + "::a_writter",
    new a_writter_t( *db_connection ) );
  std::auto_ptr< a_handler_t > a_handler_ptr(
    coop_name + "::a_handler",
    new a_handler_t( *db_connection ) );

  // Агенты созданы. Создание кооперации.
  so_4::rt::agent_t * agents[] =
  {
    a_reader_ptr.release(),
    a_writter_ptr.release(),
    a_handler_ptr.release()
  };

  so_4::rt::dyn_agent_coop_t * my_coop =
    new so_4::dyn_agent_coop_t(
      coop_name.c_str(), agents,
      sizeof( agents ) / sizeof( agents[ 0 ] ) );
  so_4::rt::dyn_coop_controlled( *my_coop,
    db_connection_ptr.release() );

  // Регистрация кооперации.
  so_4::rt::dyn_agent_coop_helper_t helper( my_coop );
  if( helper.result() )
    // Кооперация не зарегистрирована.
    throw std::runtime_error(
      "unable to register cooperation" );
}

Сложный способ

Данный способ был единственным возможным до появления версии 4.2.6. Поэтому он так же описан, т.к. он применялся в реальных коммерческих проектах.

Можно сделать класс, производный от so_4::rt::dyn_agent_coop_t, который в своем деструкторе уничтожит объект db_connection.

Например такого класса кооперации:

class my_dyn_coop_t :
public so_4::rt::dyn_agent_coop_t
{
  typedef so_4::rt::dyn_agent_coop_t  base_type_t;
  private :
    std::auto_ptr< db_connection_t >  m_db_connection_ptr;

  public :
    my_dyn_coop_t(
      const char * coop_name,
      so_4::rt::agent_t ** agents,
      size_t agent_count,
      db_connection_t * db_connection )
      :
        base_type_t( coop_name, agents, agent_count ),
        m_db_connection_ptr( db_connection )
    {
    }

    virtual ~my_dyn_coop_t()
    {
      // Объект db_connection будет уничтожен
      // классом std::auto_ptr
    }
};

Пример использования подобного класса:

// Функция создания динамической кооперации
// которая должна осуществлять работу с указанной
// базой данных.
// В случае ошибок порождаются исключения.
void
create_db_coop(
  // Имя кооперации.
  const std::string & coop_name,
  // Параметры подключения к БД.
  const db_connection_params_t & connection_params
) throw( std::exception )
{
  // Для очистки ресурсов при исключениях
  // используется std::auto_ptr

  // Подключение к БД.
  std::auto_ptr< db_connection_t > db_connection_ptr(
    new db_connection_t( connection_params ) );

  // Соединение с БД установлено. Создание агентов.
  std::auto_ptr< a_reader_t > a_reader_ptr(
    coop_name + "::a_reader",
    new a_reader_t( *db_connection ) );
  std::auto_ptr< a_writter_t > a_writter_ptr(
    coop_name + "::a_writter",
    new a_writter_t( *db_connection ) );
  std::auto_ptr< a_handler_t > a_handler_ptr(
    coop_name + "::a_handler",
    new a_handler_t( *db_connection ) );

  // Агенты созданы. Создание кооперации.
  so_4::rt::agent_t * agents[] =
  {
    a_reader_ptr.release(),
    a_writter_ptr.release(),
    a_handler_ptr.release()
  };

  my_dyn_coop_t * my_coop = new my_dyn_coop_t(
    coop_name.c_str(), agents,
    sizeof( agents ) / sizeof( agents[ 0 ] ),
    db_connection_ptr.release() );

  // Регистрация кооперации.
  so_4::rt::dyn_agent_coop_helper_t helper( my_coop );
  if( helper.result() )
    // Кооперация не зарегистрирована.
    throw std::runtime_error(
      "unable to register cooperation" );
}

Документация по SObjectizer. Последние изменения: Thu Jan 12 10:52:50 2006. Создано системой  doxygen 1.4.6-NO
Hosted by uCoz