воскресенье, 8 июня 2014 г.

[prog.c++] Синхронность в SObjectizer: всего-то спустя 12 лет... :)

То, о чем мне так долго говорили большевики все вокруг, нашло таки свое воплощение в жизни :) В SObjectizer появилось синхронное взаимодействие между агентами. Реализовано оно на основе C++11 классов std::promise и std::future. Что дает возможность делать не просто синхронное взаимодействие, но и более хитрые варианты.

Пока это всего лишь черновой вариант, который был опробован всего на одном компиляторе, и над которым еще предстоит работать напильником. Но начало уже положено, что не может не радовать.

Полный пример использования синхронного взаимодействия можно увидеть здесь. А вот небольшая выжимка:

Ключевые фрагменты агента, который предоставляет синхронный сервис:

virtual void
so_define_agent()
   {
      so_subscribe( m_self_mbox )
            .service( &a_convert_service_t::svc_convert );
   }

std::string
svc_convert( const so_5::rt::event_data_t< msg_convert > & evt )
   {
      std::cout << "svc_convert called: value=" << evt->m_value
            << std::endl;

      std::ostringstream s;
      s << evt->m_value;

      return s.str();
   }

Ключевые фрагменты агента, который обращается к синхронным сервисам других агентов. Параметры для синхронного сервиса все равно нужно передавать в виде динамически созданного объекта, т.к. их доставка осуществляется через очередь сообщений обычным для SObjectizer-а способом.

virtual void
so_evt_start()
   {
      auto hello =
         //NOTE: it could be a method of agent_t.
         so_5::rt::service< std::string >( m_svc_mbox )
               .request< msg_hello_svc >();

      auto convert =
         so_5::rt::service< std::string >( m_svc_mbox )
               .request( new msg_convert( 42 ) );

      std::cout << "hello_svc: " << hello.get() << std::endl;
      std::cout << "convert_svc: " << convert.get() << std::endl;

      std::cout << "sync_convert_svc: "
            << so_5::rt::service< std::string >( m_svc_mbox )
                  .sync_request( new msg_convert( 1020 ) )
            << std::endl;

      // More complex case with conversion.
      auto svc_proxy = so_5::rt::service< std::string >( m_svc_mbox );

      // These requests should be processed before next 'sync_request'...
      auto c1 = svc_proxy.request( new msg_convert( 1 ) );
      auto c2 = svc_proxy.request( new msg_convert( 2 ) );

      // Two previous request should be processed before that call.
      std::cout << "sync_convert_svc: "
            << svc_proxy.sync_request( new msg_convert( 3 ) )
            << std::endl;

      // But their value will be accessed only now.
      std::cout << "convert_svc: c2=" << c2.get() << std::endl;
      std::cout << "convert_svc: c1=" << c1.get() << std::endl;

      so_environment().stop();
   }

Пока выглядит многословно. Но, думаю, если тщательно разобраться с С++11 variadic templates и std::forward, объем писанины можно будет посократить.

Комментариев нет: