LINUX.ORG.RU

анонс: SObjectizer 5.3.0

 


2

6

SObjectizer — это реализация модели акторов для C++, позволяющая программировать на C++ с использованием работающих на разных нитях агентов, общающихся между собой посредством сообщений. SObjectizer существенно упрощает разработку событийно-ориентированных приложений, для параллельной и независимой обработки событий в которых требуется многопоточность и/или распределенность. SObjectizer использовался для создания как для мелких утилит, так и серьезных распределенных приложений, работающих под большой нагрузкой в режиме 24x7.

Последние несколько лет SObjectizer развивается на SourceForge как OpenSource проект под BSD-лицензией. Версия 5.3.0 является очередным существенным шагом по наращиванию возможностей SObjectizer при одновременном упрощении его использования.

В версии 5.3.0 произведены значительные улучшения:

  • добавлена возможность организации синхронного взаимодействия агентов: инициатор запроса может синхронно ожидать результата на объекте std::future, в то время как обработчик запроса работает обычным образом на своей рабочей нити;
  • более активно используются лямбда-функции, введенные в C++11. Например, теперь обработчики событий могут быть заданы посредством лямбда-функций, что позволяет уменьшить объем кода агентов;
  • добавлена возможность создавать ad-hoc агентов, формируя агента из лямбда-функций, а не описывая отдельный, унаследованный от so_5::rt::agent_t, класс;
  • доработана модель реагирования на выпущенные из обработчиков событий исключения.

Эта версия так же содержит несколько более мелких исправлений, улучшений, доработок и примеров.

Традиционный пример “Hello, World” теперь может быть записан вот так:

so_5::api::run_so_environment(
  []( so_5::rt::so_environment_t & env ) {
    auto coop = env.create_coop( "hello" );
    coop->define_agent().on_start( [&env]() {
      std::cout << "Hello, World" << std::endl;
      env.stop();
    } );
    env.register_coop( std::move( coop ) );
  } );
А более интересный пример ping_pong, где каждый агент работает на контексте своей собственной нити, вот так:
int pings_left = 10000;
so_5::api::run_so_environment(
  [&pings_left]( so_5::rt::so_environment_t & env )
  {
    struct msg_ping : public so_5::rt::signal_t {};
    struct msg_pong : public so_5::rt::signal_t {};

    auto mbox = env.create_local_mbox();
    auto coop = env.create_coop( "ping_pong",
       so_5::disp::active_obj::create_disp_binder( "active_obj" ) );
    coop->define_agent()
      .on_start( [mbox]() { mbox->deliver_signal< msg_ping >(); } )
      .on_event( mbox, so_5::signal< msg_pong >,
        [&pings_left, &env, mbox]() {
          if( --pings_left > 0 )
            mbox->deliver_signal< msg_ping >();
          else
            env.stop();
        } );
    coop->define_agent()
      .on_event( mbox, so_5::signal< msg_ping >,
        [mbox]() { mbox->deliver_signal< msg_pong >(); } );
    env.register_coop( std::move( coop ) );
  },
  []( so_5::rt::so_environment_params_t & params )
  {
    params.add_named_dispatcher( "active_obj", so_5::disp::active_obj::create_disp() );
  } );

Версия распространяется в виде сборки so-201407-00, в которую кроме SObjectzer 5.3.0 входит еще несколько SObjectizer-библиотек, предназначенных для разработки больших, распределенных приложений на основе SObjectizer, а именно:

  • so_log, служащая оберткой над ACE Logging и упрощающая логирование для агентов;
  • so_sysconf, позволяющая собирать большое приложение из маленьких кусочков, оформленных в виде dll/so-библиотек;
  • so_5_transport, оформляющая работу с TCP/IP соединениями в виде транспортных SObjectizer-агентов;
  • mbapi, являющаяся высокоуровневой библиотекой для обмена сообщениями между агентами или между компонентами распределенного приложения.

Релизная сборка может быть загружена с SourceForge в виде архива или же взята из svn-репозитория.

Wiki-раздел SObjectizer-а на SourceForge содержит более подробную информацию как об особенностях версии 5.3.0, так и о самом SObjectizer и его основах.

★★★★★
Ответ на: комментарий от bj

В смысле, нет багов — нет проблем.

Ну здесь только время покажет. Баги были, исправлялись. Наверняка есть еще. Как найдутся, так и исправим.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от bj

В смысле, нет багов — нет проблем.

Нормальные программисты по определению являются оптимистами.

Тем более, что основания для оптимизма есть. Последний анонс касался so_4. Тогда было понятно, что so_5 должен быть каким-то другим, но каким никто не знал. За прошедшее время so_5 был спроектирован, реализован, опробован в боевых условиях. Собрана команда, которая им занимается. Документация для so_5 сейчас пишется сразу на английском языке (в прошлом мы ошиблись, делая ее сначала на русском). Ну и у меня есть возможность работать над SObjectizer-ом full-time, чего уже очень давно не было, раньше в намного большем приоритете были проекты, в которых SObjectizer использовался. В общем, ситуация совсем другая, чем шесть лет назад.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

В общем, ситуация совсем другая, чем шесть лет назад.

Это правда. Хайп на экторы сходит на нет, появилась хорошие библиотеки с достаточными сообществами.

bj
()
Ответ на: комментарий от eao197

Ну и какая разница для вас будет в том, что so_5::disp::active_obj::create_disp — это статический метод класса active_obj в пространстве имен so_5::disp. А не свободная функция в пространстве имен so_5::disp::active_obj.

Такая, что мне не нужно копипастить её в свой новый класс. И кстати, раз уж она зависит от типа с которым работает (или возвращает), то не должна быть статической или свободной, а должна быть членом фабрики.

С классами даже хуже. Просто так using namespace не сделаешь.

С классами просто замечательно. Можно получить готовый настроенный объект из фабрики. Можно прикрутить декоратор. Можно передать объект в качестве параметра... да чего только нельзя делать с классами? А вот с неймспесами можно только копипастить.

Какие-то старые модули в этих проектах работают на so_4, какие-то новые на so_5.

Зоопарк. Пишите в старых проектах на старых либах в рамках поддержки. Для новых сделайте новую ветку и колхозьте там сколько душе угодно. Впрочем, хозяин - барин.

Ну и вам не нужно свой вариант делать

Да ну? Точно-точно? Вот вы прям пришли, увидели что мне надо и запилили?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Вы сделали мой день! :)

И кстати, раз уж она зависит от типа с которым работает (или возвращает), то не должна быть статической или свободной, а должна быть членом фабрики.

Она и есть фабрика :) Или по фен-шую сейчас фабрику нужно делать через еще одну фабрику. А она, в свою очередь через еще одну???

Можно получить готовый настроенный объект из фабрики. Можно прикрутить декоратор. Можно передать объект в качестве параметра...

Сколько еще слов из GoF вы сможете впихнуть в одно предложение?

Вот вы прям пришли, увидели что мне надо и запилили?

Не-не-не. Мы увидили, что нам нужно, запилили и залили результат на SourceForge. Не более того.

Если вам это надо, вы сможете использовать. Если не надо — не будете.

Ну а как на счет вопроса про замену event_data_t<msg_pong> чем-то на трайтах и тайпдефах? Что-нибудь вменяемое сможете показать или это просто пук в лужу был?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от bj

Хайп на экторы сходит на нет, появилась хорошие библиотеки с достаточными сообществами.

Мы сейчас про плюсовые библиотеки говорим или вообще?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Хотя не очень понимаю, зачем в таких проектах акторы.

По вашему, на C++ не писали больших многопоточных приложений? ;)

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

По вашему, на C++ не писали больших многопоточных приложений?

Мировая практика говорит, что экторы в этом не слишком хорошо помогают.

bj
()
Ответ на: комментарий от bj

Про плюсовые конечно.

Например?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от bj

Мировая практика говорит, что экторы в этом не слишком хорошо помогают.

Могли бы развернуть? Или ссылочку дать на какие-то материалы, это доказывающие?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Или по фен-шую сейчас фабрику нужно делать через еще одну фабрику

Конечно. Называется абстрактная фабрика. Ссылку в википедии дать?

Если вам это надо, вы сможете использовать. Если не надо — не будете.

Ой ой, какие мы обидчивые.

про замену event_data_t<msg_pong> чем-то на трайтах и тайпдефах?

Я просто предлагал вам завернуть ваши километровые типы в тайпдефы для класса. Ведь класс у вас работает только с event_data_t<msg_pong>. Каждый раз это писать - замучаешься, да и глаза мозолит эта пестрота. А что касается трайтов, то можно сделать трайт на <msg_pong> как pong<msg_pong>, после чего уже не таскать это <msg_pong> везде, а указывать что-то вроде pong::event_data.

Технически это конечно ничего не изменит, но читать код станет намного приятнее.

no-such-file ★★★★★
()
Ответ на: комментарий от eao197

Писали и пишут. И без всяких акторов=) Но вопрос в том, зачем старым проектам новые велосипеды.

anonymous
()
Ответ на: комментарий от no-such-file

Конечно. Называется абстрактная фабрика. Ссылку в википедии дать?

Спасибо, не надо. Любители паттернов проектирования давно известны своим умением доводить простые вещи до маразма.

Я просто предлагал вам завернуть ваши километровые типы в тайпдефы для класса.

Например, как?

Ведь класс у вас работает только с event_data_t<msg_pong>. Каждый раз это писать - замучаешься, да и глаза мозолит эта пестрота.

Он там написан всего один раз.

А что касается трайтов, то можно сделать трайт на <msg_pong> как pong<msg_pong>, после чего уже не таскать это <msg_pong> везде, а указывать что-то вроде pong::event_data.

Т.е. пользователю сначала нужно будет определить msg_pong, затем где-то еще pong<msg_pong>, а потом оперировать pong::event_data.

Вместо того, что бы иметь просто msg_pong и event_data_t<msg_pong>. В чем выигрыш?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

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

anonymous
()
Ответ на: комментарий от anonymous

Но вопрос в том, зачем старым проектам новые велосипеды.

Ну вот, скажем, Adobe Lightroom, далеко не новый проект. Многопоточность задействует по полной программе. Судя по последним версиям, переход на какой-то более вменяемый инструментарий его разработчикам бы явно не помешал.

Или Lightroom нужно на Haskell-е переписать?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

Акторы бывают разные. У нас это решается привязкой агента к соответствующему диспетчеру.

Если агенту нужна отдельная нить, он привязывается к диспетчеру active_obj, ему выделяется нить и агент становится полноценным активным объектом.

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

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

Т.о. посредством диспетчеров active_obj и one_thread в приложении можно создавать сотни тысяч агентов, при желании и наличии памяти — миллионы. Правда, все агенты должны работать как конечные автоматы — получил сообщение, изменил свое состояние, вернул управление.

По поводу сопрограмм. Нам не нужны были, мы их и не делали. Если кому-то потребуются и будут идеи о том, как это нормально вшить в SO, то можно подумать и сделать. Но, полагаю, сопрограммы будет проще встраивать в libcppa, там идеология ближе к таким вещам.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Например, как?

Например вместо

 a_pinger_t( so_5::rt::so_environment_t & env,
    const so_5::rt::mbox_ref_t & mbox,
    int pings_left )
    : so_5::rt::agent_t( env )
    , m_mbox( mbox )
    , m_pings_left( pings_left )
    {}


я хочу видеть

 a_pinger_t( environment & env, Mbox & mbox, int pings_left )
    : agent( env )
    , m_mbox( mbox )
    , m_pings_left( pings_left )
    {}

Мне не интересно на данном этапе что такое environment в данном случае. Так мне сразу понятно что это какое-то окружение и не нужно ломать глаза обо все эти ваши so_5::rt:: и т.д. которые не имеют отношения к сути.

Он там написан всего один раз.

Ну и что?

В чем выигрыш?

Во-первых в читаемости кода. Во-вторых, если мне вдруг захочется вместо <msg_pong> использовать <msg_superpong>, мне что, грепать по коду все применения? Спасибо, я лучше один раз определю трайт, или хотя бы тайпдеф.

доводить простые вещи до маразма.

Это вы доводите до маразма со своими неймспейсами на каждый чих, шаблонами не по делу и прочим мусором в коде.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от eao197

Чтобы не писать полностью sobjectizer_environment_t. Просто environment неоднозначно, окружения могут быть разные.

И?

so5::Environment;
so5rt::Environment;
someshit::Environment;

--- разные окружения.

А мне лень нажимать shift

А жать «shift»+"-" не лень?

korvin_ ★★★★★
()
Ответ на: комментарий от no-such-file

я хочу видеть

using namespace so_5::rt;
...
a_pinger_t( so_environment_t & env, const mbox_ref_t & mbox, int pings_left )
  : agent_t( env )
  , m_mbox( mbox )
  , m_pings_left( pings_left )
  {}

Споры про неприятие вами конкретной нотации не в счет. Мне, например, ни нотация в библиотеке ACE, но нотация в Boost-е не нравится, тем не менее, пользоваться этими библиотеками сей прискорбный факт не мешает. Ни мне, ни куче других разработчиков.

Он там написан всего один раз.

Ну и что?

Ну и какой смысл писать тайпдеф на одно использование?

Во-вторых, если мне вдруг захочется вместо <msg_pong> использовать <msg_superpong>, мне что, грепать по коду все применения? Спасибо, я лучше один раз определю трайт, или хотя бы тайпдеф.

Вы так и не показали, как все это будет выглядеть.

BTW, сейчас написание const event_data_t<MSG> & требуется только в отдельный случаях, когда пользователю нужен доступ к метаданным, связанным с экземпляром сообщения. Если нужно просто сообщение, то достаточно задекларировать обработчик вот так:

void some_agent::some_event( const MSG & );

Более того, с учетом факта, что msg_pong в обсуждаемом примере — это сигнал, не несущий никаких данных внутри, то код агента в традиционном C++ стиле был бы записан так:

virtual void so_define_agent()
{
  so_subscribe( mbox ).event( so_5::signal< msg_pong >, &a_pinger_t::evt_pong );
}

void evt_pong()
{
  ...
}

Это вы доводите до маразма со своими неймспейсами на каждый чих

Я записываю код так, как удобно мне. Использование нейспейсов упрощает сопровождение кода, так что это уже привычка. Однако, наличие в C++ конструкции using namespace позволяет пользователям писать так, как им это удобно.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от korvin_

А жать «shift»+"-" не лень?

С учетом того, что я уже 15 лет пользуюсь lower_case нотаций доказывает, что нет.

Поразительно много споров вокруг нотации. В C++ уже появился общепринятый стандарт?

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

using namespace so_5::rt;

Стоило городить неймспейсы, чтобы их выкинуть?

Споры про неприятие вами конкретной нотации не в счет

Комментаторов не поймешь :)

С таким подходом конечно не поймёшь. Вы код для себя пишите или для людей вообще? Если для себя, то зачем запостили сюда анонс?

А если для людей, то прочистите уши, засуньте свои 'жри или вали' в одно место и сделайте так, чтобы код был приемлемым по виду не только для вас, но и для окружающих.

Ну или не сетуйте тогда, что вас тут не ценят и тычут, понимаешь, перлом.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Стоило городить неймспейсы, чтобы их выкинуть?

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

Вы код для себя пишите или для людей вообще?

Для себя. «Люди вообще» — это никто, в сущности.

Если для себя, то зачем запостили сюда анонс?

Мало ли. Вруг кому-нибудь еще пригодится.

то прочистите уши, засуньте свои 'жри или вали' в одно место и сделайте так, чтобы код был приемлемым по виду не только для вас, но и для окружающих.

Может начнете с того, что попробуйте отвечать за себя. Вы здесь много чего наговорили и насоветовали: трайты, тайпдефы, фабрики, декораторы... Только как дело до конкретики доходит, так разговоры про «людей вообще» или «лень _t писать».

Ну или не сетуйте тогда, что вас тут не ценят и тычут, понимаешь, перлом.

Это не сетование было, а иллюстрация того, что как не напиши библиотеку, больше всего разговоров будет про то, почему so_5::rt::so_environment_t, а не so5rt::Environment. Что, собственно, не удивительно и давно замечено, ибо ляпнуть что-нибудь не подумав намного проще и приятнее для говорящего.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Многопоточность != акторам. Строго говоря, вы можете сопрограммки переключать в одном треде и получить такую же производительность. А если еще логика системы позволяет просто параллельно запустить инстансы таких процессов по числу ядер, то тут вы вряд ли обгоните это дело своими тредами. Ортогональные это вещи

anonymous
()
Ответ на: комментарий от eao197

«Люди вообще» — это никто, в сущности.

Поосторожнее с такими заявлениями, могут экстремизм пришить.

Может начнете с того, что попробуйте отвечать за себя.

Я уже озвучил, что мне лично и конкретно не нравится в вашем коде. В общем мне лично в нем не нравится конкретно всё. Я лично считаю этот код конкретным эталоном того, как не надо делать.

Это не сетование было, а иллюстрация того, что как не напиши библиотеку, больше всего разговоров будет про то, почему so_5::rt::so_environment_t, а не so5rt::Environment.

Ок. Как и зачем было принято решение использовать неймспейс rt с соответствующим определением environment вместо того чтобы иметь одну фабрику в верхнем неймспейсе, которая выдаёт объект rt (или some_other_thing), который в свою очередь выдаёт соответствующий environment?

Хотелось бы так же узнать, зачем функция deliver_signal< msg_ping >() принимает msg_ping как параметр шаблона, а не как просто параметр функции? Она специализируется по этому параметру?

no-such-file ★★★★★
()
Ответ на: комментарий от eao197

Агент по определению является активным объектом ;)

Этой группе выделяется своя нить, внутри которой они обрабатывают свои события.

Во, уже интереснее. А как они диспатчаться? Не будут ли какие-то агенты простаивать и пр.?

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

Сопрограммы могли бы помочь избежать написания этого в коде напрямую, переместив это дело под капот. В смысле переключались бы при отправки сообщения, например или специальными инструкциями.

anonymous
()
Ответ на: комментарий от no-such-file

Стоило городить неймспейсы, чтобы их выкинуть?

Выкинуть или нет - решает клиент. Если у него нет конфликтов имен в данном случае, то почему бы не импортнуть имена в текующую область видимости? Как вы пишите на нормальных языках вообще? Или если вместо using so_5::rt:blablabla писать import so_5.rt.blablabla, то все сразу меняется?

anonymous
()
Ответ на: комментарий от anonymous

Многопоточность != акторам

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

Про производительность полностью согласен.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Если у него нет конфликтов имен в данном случае

Но ведь можно писать так, чтобы конфликтов не было в любом случае. Достаточно просто не хардкодить всё в неймспейсы, а выдавать нужные объекты по запросу.

no-such-file ★★★★★
()
Ответ на: комментарий от anonymous

Агент по определению является активным объектом ;)

У «агента» нет, насколько я помню, общепринятного определения. В терминологии FIPA агент, емнип, — это вообще большая штука, которая может быть реализованна не то, целым процессом, а даже группой процессов.

Поэтому одно время SObjectizer даже позицианировался как фреймворк для микроагентного программирования.

Этой группе выделяется своя нить, внутри которой они обрабатывают свои события.

Во, уже интереснее. А как они диспатчаться? Не будут ли какие-то агенты простаивать и пр.?

Все агенты вызываются только, если к ним приходят сообщения. Фактически, у каждой рабочей нити есть очередь сообщений, куда складываются сообщения для всех агентов, которые привязаны к данной нити. Нить берет очередное сообщение и дергает агента-получателя, после того, как очередной агент отработал, берется следующее сообщение и дергается следующий получатель и т.д.

Если для какого-то агента нет сообщений, то он и не вызывается.

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

Сопрограммы могли бы помочь избежать написания этого в коде напрямую, переместив это дело под капот. В смысле переключались бы при отправки сообщения, например или специальными инструкциями.

Это понятно. Другое дело, что нам не особо было нужно. А разговоры об этом заходили чуть ли не с самого первого упоминания SObjectizer-а на публике.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Все агенты вызываются только, если к ним приходят сообщения. Фактически, у каждой рабочей нити есть очередь сообщений, куда складываются сообщения для всех агентов, которые привязаны к данной нити. Нить берет очередное сообщение и дергает агента-получателя, после того, как очередной агент отработал, берется следующее сообщение и дергается следующий получатель и т.д.

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

anonymous
()
Ответ на: комментарий от no-such-file

Я лично считаю этот код конкретным эталоном того, как не надо делать.

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

Ок. Как и зачем было принято решение использовать неймспейс rt с соответствующим определением environment вместо того чтобы иметь одну фабрику в верхнем неймспейсе, которая выдаёт объект rt (или some_other_thing), который в свою очередь выдаёт соответствующий environment?

В SO-4 было два основных пространства имен: api и rt (rt — это сокращение от run-time). В пространстве имен api располагались API-шные функции для управления SObjectizer-ом: запуск, останов, отсылка сообщения и т.д. В пространстве имен rt располагались основные типы, которые нужны были как пользователю SObjectizer, так и самому SObjectizer — агенты, кооперации, стандартные сообщения и пр. лабуда.

При разработке SO-5 этот принцип был сохранен для того, чтобы проще было переписывать код, который был заточен под SO-4. Только в SO-5 пространство имен api сильно уменьшилось по своему наполнению. А вот rt свое назначение сохранило. Поэтому определение всех классов, связанных с системой исполнения SO-5 (окружение для run-time, базовый класс агента, класс кооперации, интерфейс mailbox-а и пр.).

Имя so_environment_t — это имя интерфейса, предоставляющего методы для управления run-time-ом SObjectizer-а, поэтому он включен в so_5::rt.

Конкретная реализация so_environment_t скрыта от пользователя внутри run-time. Пользователь получает ссылку на уже готовый so_environmen_t при обращении к run_so_environment. Поэтому здесь пользователю не нужны никакие фабрики.

Хотелось бы так же узнать, зачем функция deliver_signal< msg_ping >() принимает msg_ping как параметр шаблона, а не как просто параметр функции? Она специализируется по этому параметру?

msg_ping — это имя типа, который определяется вот так:

struct msg_ping : public so_5::rt::signal_t {};
Поскольку msg_ping — это тип, нельзя передать тип параметром функции. Можно передать параметром экземпляр этого типа (или ссылку/указатель на экземпляр).

Однако, в SO-5 есть два типа сообщений: собственно сообщения с данными внутри и сигналы. Сигналы — это частный случай сообщения, когда важен сам факт наличия какого-то сообщения, но нет никаких связанных с ним данных. Для отсылки сообщения пользователь должен создать экземпляр и передать его в deliver_message параметром. Например, вот так:

struct msg_hello : public so_5::rt::message_t
{
  std::string m_greetings;
  msg_hello( std::string greetings ) : m_greetings( std::move(greetings) )
  {}
};
...
mbox->deliver_message( new msg_hello( "Hello, World!" ) );
Однако, в случае сигнала передавать нечего. Поэтому, чтобы не писать как-то так:
mbox->deliver_message( static_cast< msg_ping >(nullptr) );
мы пишем вот так:
mbox->deliver_signal< msg_ping >();

eao197 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

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

Конечно. Просто агент определяет нужные ему сообщения и отсылает их сам себе. Либо обычным образом, либо с задержкой по таймеру и/или повтором с заданным темпом.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Конкретная реализация so_environment_t скрыта от пользователя внутри run-time

Ок. Почему же тогда оставлен rt? Для совместимости? Вы же сами раньше утверждали, что есть конфликт имён для сущностей из rt и не из rt?

msg_ping — это имя типа

Для отсылки сообщения пользователь должен создать экземпляр и передать его в deliver_message параметром

Тем не менее, в этом случае параметр шаблона просто выводится. Зачем же функция в принципе имеет этот параметр? Предполагается, что сообщение может быть любого типа, а не унаследовано от so_5::rt::signal_t или что там у вас?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Ок. Почему же тогда оставлен rt? Для совместимости? Вы же сами раньше утверждали, что есть конфликт имён для сущностей из rt и не из rt?

rt оставлен для упрощения переписывания прикладного кода с SO-4 на SO-5. Такое переписывание эпизодически случается, но тотального характера не имеет.

Вообще namespace используются в SO для того, чтобы не думать о конфликте имен. Так, в пространствах имен so_5::disp::active_obj, so_5::disp::active_group и so_5::disp::one_thread есть функци-фабрики с одинаковыми именами create_disp/create_disp_binder. Но нас это не заботит, т.к. они находятся в разных пространствах имен.

Тем не менее, в этом случае параметр шаблона просто выводится.

Параметр выводится когда есть что передавать параметром функции, как вот здесь:

mbox->deliver_message( new msg_hello( "Hello, World!" ) );

А вот когда нет экземпляра сообщения, то нечего передавать в качестве параметра функции. Соответственно, компилятору не из чего вывести тип параметра шаблона. Поэтому и запись:

mbox->deliver_signal< msg_ping >();

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

вот когда нет экземпляра сообщения, то нечего передавать в качестве параметра функции

Почему не передавать просто пустой объект? Конструировать его можно статическим методом базового класса - небольшая цена за избавление от шаблона.

Так, в пространствах имен so_5::disp::active_obj, so_5::disp::active_group и so_5::disp::one_thread есть функци-фабрики с одинаковыми именами create_disp/create_disp_binder.

Но ведь можно было сделать три класса, а не три неймспейса и получать объекты этих классов из фабрики. Тогда все эти три класса, имея общего родителя, можно было бы использовать более-менее взаимозаеняемо. И я, например, мог бы получив объект active_obj завернуть его в свой декоратор и подсунуть декоратор вместо active_obj. А сейчас мне нужно будет скопипастить so_5::disp::active_obj и исправить что нужно. Дублирование кода налицо.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Почему не передавать просто пустой объект? Конструировать его можно статическим методом базового класса - небольшая цена за избавление от шаблона.

Все сообщения, которые ходят между агентами в SObjectizer должны быть динамически созданными объектами. Т.е. в deliver_message передается указатель, а не экземпляр сообщения. Так что просто писать вот так:

mbox->deliver_message( msg_ping() );
не получится, т.к. deliver_message ждет указатель. Да и существенного выигрыша между вариантами я не вижу:
mbox->deliver_signal( msg_ping() );
mbox->deliver_signal< msg_ping >();

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

Неймспейсы нужны не только для того, чтобы спрятать в них функции create_disp, но и чтобы спрятать туда детали реализации конкретных диспетчеров.

Что до фабрик, то в C++, в отличии от Java, без разницы, чем является фабрика — классом или свободной функцией. Точно так же можно оперировать указателями на функции-фабрики, как и указателями на объекты-фабрики. Так что сделать абстрактную фабрику, которая будет скрывать конкретный экземпляр create_disp — не проблема.

А для create_disp_binder это, вообще вряд ли нужно, там почти у каждой из функций свой набор параметров.

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Кстати, а события от таймера есть? Т.е., грубо говоря, просим систему посылать нам сообщения, скажем, раз в секунду и нам они идут с такой регулярностью.

anonymous
()
Ответ на: комментарий от anonymous

Кстати, а события от таймера есть? Т.е., грубо говоря, просим систему посылать нам сообщения, скажем, раз в секунду и нам они идут с такой регулярностью.

Конечно. Вот пример с описаниями что к чему

eao197 ★★★★★
() автор топика
Ответ на: комментарий от eao197

Да и существенного выигрыша между вариантами я не вижу:

Выигрыш в отказе от шаблона, т.е. от генерации кода на каждый тип сообщения. Ну и плюс удобство - тип указателя на эту функцию не меняется и его можно без костылей сохранить или передать в другую функцию.

не только для того, чтобы спрятать в них функции create_disp, но и чтобы спрятать туда детали реализации конкретных диспетчеров.

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

Так что сделать абстрактную фабрику, которая будет скрывать конкретный экземпляр create_disp — не проблема

Я бы не был так уверен. Разные create_disp лежат в разных неймспейсах, а фабрика должна возвращать единственный тип (родительского объекта).

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Выигрыш в отказе от шаблона, т.е. от генерации кода на каждый тип сообщения. Ну и плюс удобство - тип указателя на эту функцию не меняется и его можно без костылей сохранить или передать в другую функцию.

Функции отсылки сообщений/сигналов должны быть шаблонными, т.к. из параметра шаблона выводится std::type_index, который нам нужен для определения получателей сообщения.

Да и задачи уменьшать объем генерируемого кода у нас не было.

Что до указателей на функцию, то в современном C++ через std::function и лямбды можно получить указатель на что угодно.

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

Неймспейс — это место, где располагается код. Т.е. вопрос не в том, откуда что получать, а где что хранить, чтобы потом не иметь проблем при сопровождении и развитии.

Я бы не был так уверен. Разные create_disp лежат в разных неймспейсах, а фабрика должна возвращать единственный тип (родительского объекта).

Не вижу проблемы. Определяете std::function<so_5::rt::dispatcher_unique_ptr_t()> и можете хранить в нем указатели на create_disp из разных неймспейсов.

eao197 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.