SlideShare a Scribd company logo
1 of 217
Download to read offline
Погружение в SObjectizer-5.5
SObjectizer Team, февраль 2015
Вводная часть
SObjectizer Team, февраль 2015
О чем пойдет речь?
О чем пойдет речь?
Об инструменте для
многопоточного программирования.
SObjectizer Team, февраль 2015
О чем пойдет речь?
Об инструменте для
многопоточного программирования.
Которое считается сложным...
SObjectizer Team, февраль 2015
О чем пойдет речь?
Об инструменте для
многопоточного программирования.
Которое считается сложным.
Не просто сложным,
SObjectizer Team, февраль 2015
О чем пойдет речь?
Об инструменте для
многопоточного программирования
Которое считается сложным.
Не просто сложным,
а ОЧЕНЬ СЛОЖНЫМ занятием.
SObjectizer Team, февраль 2015
Ведь постоянно иметь дело c
низкоуровневыми примитивами вроде:
SObjectizer Team, февраль 2015
Ведь постоянно иметь дело c
низкоуровневыми примитивами вроде:
● native threads
● critical sections, semaphores, mutexes, condition
variables, monitors
● thread local storages
● atomic variables, spinlocks...
SObjectizer Team, февраль 2015
Ведь постоянно иметь дело с
низкоуровневыми примитивами вроде:
● native threads
● critical sections, semaphores, mutexes, condition variables,
monitors
● thread local storages
● atomic variables, spinlocks...
И последствиями их применения в виде
тупиков и гонок - это же очень сложно...
SObjectizer Team, февраль 2015
Ведь постоянно иметь дело c
низкоуровневыми примитивами вроде:
● native threads
● critical sections, semaphores, mutexes, condition variables,
monitors
● thread local storages
● atomic variables, spinlocks...
И последствиями их применения в виде
тупиков и гонок - это же очень сложно...
Правильно?
SObjectizer Team, февраль 2015
Правильно!
SObjectizer Team, февраль 2015
Правильно!
Однако, при
использовании
SObjectizer...
SObjectizer Team, февраль 2015
SObjectizer Team, февраль 2015
Мы практически ни с чем
из перечисленного
не сталкиваемся
SObjectizer позволяет организовать
многопоточное приложение в виде
совокупности объектов-агентов.
SObjectizer Team, февраль 2015
SObjectizer позволяет организовать
многопоточное приложение в виде
совокупности объектов-агентов.
SObjectizer Team, февраль 2015
Взаимодействующих друг с другом
только посредством
асинхронных сообщений.
Каждый агент получает свой собственный
контекст, на котором выполняет обработку
своих сообщений.
SObjectizer Team, февраль 2015
Каждый агент получает свой собственный
контекст, на котором выполняет обработку
своих сообщений.
Агент привязан к своему контексту и
может не заботиться о защите своих
данных в многопоточном окружении.
SObjectizer Team, февраль 2015
Каждый агент получает свой собственный
контекст, на котором выполняет обработку
своих сообщений.
Агент привязан к своему контексту и может
не заботиться о защите своих данных в
многопоточном окружении.
Эта защита выполняется автоматически
самим SObjectizer-ом!
SObjectizer Team, февраль 2015
Да!
SObjectizer Team, февраль 2015
Да! Это очень напоминает Actor Model
SObjectizer Team, февраль 2015
Да! Это очень напоминает Actor Model
Потому что SObjectizer создавался
и под ее влиянием...
SObjectizer Team, февраль 2015
Да! Это очень напоминает Actor Model
Потому что SObjectizer создавался
и под ее влиянием...
При этом SObjectizer - это небольшая C++
библиотека, в зону ответственности которой
входят:
SObjectizer Team, февраль 2015
Да! Это очень напоминает Actor Model
Потому что SObjectizer создавался
и под ее влиянием...
При этом SObjectizer - это небольшая C++
библиотека, в зону ответственности которой
входят:
SObjectizer Team, февраль 2015
● доставка сообщений внутри одного процесса и
Да! Это очень напоминает Actor Model
Потому что SObjectizer создавался
и под ее влиянием...
При этом SObjectizer - это небольшая C++
библиотека, в зону ответственности которой
входят:
SObjectizer Team, февраль 2015
● доставка сообщений внутри одного процесса и
● предоставление рабочего контекста агентам, плюс
Да! Это очень напоминает Actor Model
Потому что SObjectizer создавался
и под ее влиянием...
При этом SObjectizer - это небольшая C++
библиотека, в зону ответственности которой
входят:
SObjectizer Team, февраль 2015
● доставка сообщений внутри одного процесса и
● предоставление рабочего контекста агентам, плюс
● тонкая настройка всего этого дела
SObjectizer Team, февраль 2015
У нас не было задачи создать
еще один Erlang,
со своим компилятором,
стандартными библиотеками и
средой исполнения
SObjectizer вообще родился тогда, когда за
пределами Ericsson о Erlang мало кто знал.
SObjectizer Team, февраль 2015
SObjectizer вообще родился тогда, когда за
пределами Ericsson о Erlang мало кто знал.
SObjectizer Team, февраль 2015
В 1996-м в Гомельском КБ Системного
Программирования появилась первая
версия SCADA Objectizer.
SObjectizer вообще родился тогда, когда за
пределами Ericsson о Erlang мало кто знал.
SObjectizer Team, февраль 2015
В 1996-м в Гомельском КБ Системного
Программирования появилась первая
версия SCADA Objectizer.
Это был инструмент для задач АСУ ТП,
в котором агенты отсылали друг другу
асинхронные сообщения.
SObjectizer вообще родился тогда, когда за
пределами Ericsson о Erlang мало кто знал.
SObjectizer Team, февраль 2015
В 1996-м в Гомельском КБ Системного
Программирования появилась первая
версия SCADA Objectizer.
Это был инструмент для задач АСУ ТП,
в котором агенты отсылали друг другу
асинхронные сообщения.
А контекст для их обработки
обеспечивался диспетчером.
В 2000-м разработка SCADA Objectizer
прекратилась, коллектив распался.
Но идеи об агентах, обрабатывающих
асинхронные сообщения под управлением
диспетчера, - остались.
SObjectizer Team, февраль 2015
В 2000-м разработка SCADA Objectizer
прекратилась, коллектив распался.
Но идеи об агентах, обрабатывающих
асинхронные сообщения под управлением
диспетчера, - остались.
SObjectizer Team, февраль 2015
Поэтому, когда в 2001-м уже в компании
Интервэйл бывшие разработчики SCADA
Objectizer реализовали многопоточное GUI-
приложение, работающее с внешним
оборудованием...
SObjectizer Team, февраль 2015
...то оказалось, что в нем живет примитивная и
сильно урезанная версия SCADA Objectizer
SObjectizer Team, февраль 2015
...то оказалось, что в нем живет примитивная и
сильно урезанная версия SCADA Objectizer
Что дало толчок к разработке нового
инструмента, построенного на тех же идеях,
но уже имеющего новую реализацию...
SObjectizer Team, февраль 2015
...то оказалось, что в нем живет примитивная и
сильно урезанная версия SCADA Objectizer
Что дало толчок к разработке нового инструмента,
построенного на тех же идеях, но уже имеющего
новую реализацию...
Так в 2002-м появился SObjectizer.
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
● передачи SMS/USSD трафика;
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
● передачи SMS/USSD трафика;
● обслуживания финансовых транзакций;
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
● передачи SMS/USSD трафика;
● обслуживания финансовых транзакций;
● мониторинга параметров ПО.
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
● передачи SMS/USSD трафика;
● обслуживания финансовых транзакций;
● мониторинга параметров ПО;
В 2006-м открыт на SourceForge как
OpenSource проект под BSD-лицензией.
SObjectizer Team, февраль 2015
Долгое время SObjectizer был внутренним
инструментом компании Интервэйл.
Использовался в разработке систем:
● передачи SMS/USSD трафика;
● обслуживания финансовых транзакций;
● мониторинга параметров ПО.
В 2006-м открыт на SourceForge как
OpenSource проект под BSD-лицензией.
С 2013-го развивается на SourceForge
полностью как самостоятельный,
независимый от Интервэйл проект.
SObjectizer Team, февраль 2015
За время своего существования SObjectizer
несколько раз полностью переписывался.
SObjectizer Team, февраль 2015
За время своего существования SObjectizer
несколько раз полностью переписывался.
Далее речь пойдет о пятом поколении SObjectizer,
разработка которого началась в 2010-м.
SObjectizer Team, февраль 2015
За время своего существования SObjectizer
несколько раз полностью переписывался.
Далее речь пойдет о пятом поколении SObjectizer,
разработка которого началась в 2010-м.
А более конкретно - о версии 5.5.3, выпущенной
в феврале 2015-го.
SObjectizer Team, февраль 2015
Вся работа в SObjectizer происходит внутри
SObjectizer Environment.
SObjectizer Team, февраль 2015
Вся работа в SObjectizer происходит внутри
SObjectizer Environment.
SObjectizer Environment - это контейнер,
содержащий SObjectizer Run-Time, кооперации
агентов, почтовые ящики для обмена
сообщениями, диспетчеры и таймерную нить.
SObjectizer Team, февраль 2015
Вся работа в SObjectizer происходит внутри
SObjectizer Environment.
SObjectizer Environment - это контейнер,
содержащий SObjectizer Run-Time, кооперации
агентов, почтовые ящики для обмена
сообщениями, диспетчеры и таймерную нить.
Можно создать несколько экземпляров
SObjectizer Environment. Каждый из них будет
работать независимо от других.
SObjectizer Team, февраль 2015
SObjectizer Environment создается функцией
so_5::launch().
SObjectizer Team, февраль 2015
SObjectizer Environment создается функцией
so_5::launch().
Внутри Environment so_5::launch() запускает
экземпляр SObjectizer Run-Time и возвращает
управление после его останова.
SObjectizer Team, февраль 2015
SObjectizer Environment создается функцией
so_5::launch().
Внутри Environment so_5::launch() запускает
экземпляр SObjectizer Run-Time и возвращает
управление после его останова.
Что именно будет происходить внутри
запущенного Run-Time определяется
пользовательской стартовой функцией.
SObjectizer Team, февраль 2015
SObjectizer Environment создается функцией
so_5::launch().
Внутри Environment so_5::launch() запускает
экземпляр SObjectizer Run-Time и возвращает
управление после его останова.
Что именно будет происходить внутри
запущенного Run-Time определяется
пользовательской стартовой функцией.
В случае ошибок so_5::launch() выбрасывает
исключения.
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
Главный заголовочный
файл со всеми нужными
определениями.
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
Стартовая функция, которая
отвечает за запуск прикладной
логики приложения.
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
Созданный экземпляр Environment,
внутри которого будет работать
стартовая функция и все, что в этой
функции будет порождено.
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
Порождение Environment,
запуск Run-Time и вызов
стартовой функции init. Возврат
из launch() произойдет когда
завершат работу созданные
внутри init() прикладные агенты.
SObjectizer Team, февраль 2015
Выглядит это так:
#include <iostream>
#include <so_5/all.hpp>
void init( so_5::rt::environment_t & env ) { ... }
int main()
{
try
{
so_5::launch( &init );
}
catch( const std::exception & x )
{
std::cerr << "Exception: " << x.what() << std::endl;
}
}
Обработка ошибок, информирование о
которых выполняется посредством
исключений.
SObjectizer Team, февраль 2015
Внутри стартовой функции обычно создается
одна или несколько коопераций с прикладными
агентами.
SObjectizer Team, февраль 2015
Внутри стартовой функции обычно создается
одна или несколько коопераций с прикладными
агентами.
Кооперация - это группа агентов, которые
должны работать вместе и которые не могут
существовать друг без друга.
SObjectizer Team, февраль 2015
Внутри стартовой функции обычно создается
одна или несколько коопераций с прикладными
агентами.
Кооперация - это группа агентов, которые
должны работать вместе и которые не могут
существовать друг без друга.
Например, агенты pinger и ponger, которые
обмениваются друг с другом сообщениями ping
и pong.
SObjectizer Team, февраль 2015
Внутри стартовой функции обычно создается
одна или несколько коопераций с прикладными
агентами.
Кооперация - это группа агентов, которые
должны работать вместе и которые не могут
существовать друг без друга.
Например, агенты pinger и ponger, которые
обмениваются друг с другом сообщениями ping и
pong.
Нет смысла отдельно в pinger-е и отдельно в
ponger-е. Эти два агента должны
появляться и исчезать одновременно.
SObjectizer Team, февраль 2015
Внутри стартовой функции обычно создается
одна или несколько коопераций с прикладными
агентами.
Кооперация - это группа агентов, которые
должны работать вместе и которые не
могут существовать друг без друга.
Например, агенты pinger и ponger, которые
обмениваются друг с другом сообщениями ping
и pong.
Нет смысла отдельно в pinger-е и отдельно в
ponger-е. Эти два агента должны
появляться и исчезать одновременно.
Именно для этого и нужны кооперации!
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
Создание кооперации
происходит в три этапа.
Сначала Environment создает
экземпляр кооперации...
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
Затем кооперация
наполняется
агентами...
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
Затем кооперация
регистрируется.
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
У каждой кооперации должно быть
уникальное имя, корректность
которого проверяется внутри
register_coop().
Но можно попросить SObjectizer
самостоятельно выбрать имя для
новой кооперации.
SObjectizer Team, февраль 2015
Создание кооперации с двумя агентами:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
env.register_coop( std::move( coop ) );
}
Создав кооперацию, стартовая функция завершает свою работу.
Но Environment продолжит работать до тех пор, пока эта кооперация
не будет дерегистрирована. Либо пока не поступит команда на останов
работы Environment-а.
SObjectizer Team, февраль 2015
Что из себя представляет агент?
SObjectizer Team, февраль 2015
Что из себя представляет агент?
Начнем с самого простого агента в этом примере.
С агента ponger.
SObjectizer Team, февраль 2015
Что из себя представляет агент?
Начнем с самого простого агента в этом примере.
С агента ponger.
Его задача очень проста:
● получать сообщения ping;
● отвечать сообщениями pong.
SObjectizer Team, февраль 2015
Что из себя представляет агент?
Начнем с самого простого агента в этом примере.
С агента ponger.
Его задача очень проста:
● получать сообщения ping;
● отвечать сообщениями pong.
Но сперва определим сообщения ping и pong...
SObjectizer Team, февраль 2015
Определение сообщений:
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
SObjectizer Team, февраль 2015
Определение сообщений:
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
Каждое сообщение должно
быть представлено своим
собственным C++ классом
(структурой).
На основании информации о
типе сообщения затем
происходит диспетчеризация
сообщений и выбор
обработчиков сообщений.
SObjectizer Team, февраль 2015
Определение сообщений:
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
Все сообщения, которые переносят
какие-либо данные внутри себя,
должны быть унаследованы от
общего базового типа
so_5::rt::message_t.
Бывают еще и сообщения, которые
информацию внутри не переносят.
Это сигналы. Подробнее они
рассматриваются ниже.
SObjectizer Team, февраль 2015
Определение сообщений:
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
SObjectizer не налагает
каких-либо серьезных
ограничений на то, что
находится внутри
сообщений.
В данном случае поля m_req
и m_resp нужны только для
работы демонстрационного
примера. К особенностям
SObjectizer они отношения не
имеют.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Каждый обычный агент
должен иметь свой
собственный C++ класс.
Могут быть еще и необычные,
т.н. ad-hoc-агенты. О них речь
пойдет чуть позже.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Класс каждого обычного агента
должен наследоваться от
общего базового типа,
so_5::rt::agent_t.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Каждый агент должен быть
связан с тем Environment-ом,
в котором агенту предстоит
работать.
Поэтому ссылка на
Environment должна
передаваться в конструктор
агента. А оттуда - в
конструктор базового типа,
so_5::rt::agent_t.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Перед тем, как агент будет
зарегистрирован в составе
кооперации, SObjectizer
вызовет у него метод
so_define_agent().
В этом методе агент должен
выполнить все необходимые
настройки.
В частности, подписаться на
интересующие его
сообщения.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Агент ponger подписывается
только на одно сообщение. Это
сообщение типа ping, которое
приходит из почтового ящика с
именем “table”.
Почтовый ящик при подписке
должен указываться явно.
А вот тип сообщения SObjectizer
определяет сам по сигнатуре
обработчика сообщения.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Метод, в котором агент
обрабатывает сообщение,
называется методом-обработчиком
события. Или просто событием.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Породившее событие
сообщение передается в
метод-обработчик по
константной ссылке.
Метод-обработчик не должен
модифицировать переданный
ему экземпляр сообщения, т.к.
этот же экземпляр в данный
момент могут обрабатывать и
другие агенты.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
На сообщение ping агент
отвечает отсылкой сообщения
pong в почтовый ящик с именем
“table”.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Функция so_5::send конструирует
объект типа pong и отсылает его
в указанный почтовый ящик.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Дополнительные аргументы
so_5::send(), которые следуют
за ссылкой на почтовый ящик,
передаются в конструктор
объекта сообщения.
В данном случае это аргумент
resp для конструктора pong.
SObjectizer Team, февраль 2015
Агент ponger:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &ponger::evt_ping );
}
private :
const so_5::rt::mbox_t m_table;
void evt_ping( const ping & evt )
{
so_5::send< pong >( m_table, evt.m_req );
}
};
Агент ponger самостоятельно
получает ссылку на почтовый
ящик, который нужен для
обмена сообщениями.
В данном случае это ящик с
именем “table”, который
создается посредством вызова
create_local_mbox().
Ссылка на почтовый ящик
сохраняется внутри агента.
SObjectizer Team, февраль 2015
Агент pinger (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &pinger::evt_pong );
}
virtual void so_evt_start() override
{
so_5::send< ping >( m_table, 500 );
}
SObjectizer Team, февраль 2015
Агент pinger (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &pinger::evt_pong );
}
virtual void so_evt_start() override
{
so_5::send< ping >( m_table, 500 );
}
Агент pinger очень похож на
агента ponger-а: получает
ссылку на Environment в
конструкторе, создает ссылку
на почтовый ящик с именем
“table” и подписывается всего
на одно сообщение в
so_define_agent().
SObjectizer Team, февраль 2015
Агент pinger (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override
{
so_default_state().event( m_table, &pinger::evt_pong );
}
virtual void so_evt_start() override
{
so_5::send< ping >( m_table, 500 );
}
Но есть одно важное отличие:
метод so_evt_start().
Этот метод вызывается у
агента сразу же после того, как
агент и его кооперация будут
успешно зарегистрированы.
В этом методе агент может
выполнить свои начальные
действия.
В данном случае - отослать
первое сообщение ping.
SObjectizer Team, февраль 2015
Агент pinger (окончание):
private :
const so_5::rt::mbox_t m_table;
void evt_pong( const pong & evt )
{
if( evt.m_resp )
so_5::send< ping >( m_table, evt.m_resp - 1 );
else
so_deregister_agent_coop_normally();
}
};
SObjectizer Team, февраль 2015
Агент pinger (окончание):
private :
const so_5::rt::mbox_t m_table;
void evt_pong( const pong & evt )
{
if( evt.m_resp )
so_5::send< ping >( m_table, evt.m_resp - 1 );
else
so_deregister_agent_coop_normally();
}
};
В своем событии evt_pong
агент pinger либо продолжает
обмен сообщениями, отсылая
следующий ping.
Либо, если все ping-и уже были
отосланы, инициирует
дерегистрацию кооперации,
которой он принадлежит.
SObjectizer Team, февраль 2015
Агент pinger (окончание):
private :
const so_5::rt::mbox_t m_table;
void evt_pong( const pong & evt )
{
if( evt.m_resp )
so_5::send< ping >( m_table, evt.m_resp - 1 );
else
so_deregister_agent_coop_normally();
}
};
Кооперация может быть
дерегистрирована по разным
причинам. В данном случае
указывается, что дерегистрация
выполняется нормально, как это и
предполагалось прикладной
логикой.
После дерегистрации кооперации с
pinger-ом и ponger-ом, других
работающих коопераций не
останется. Environment завершит
свою работу и произойдет возврат
из so_5::launch().
SObjectizer Team, февраль 2015
Несколько слов о почтовых ящиках (mbox-ах)...
SObjectizer Team, февраль 2015
Несколько слов о почтовых ящиках (mbox-ах)...
В SObjectizer, в отличии от похожих
инструментов, вроде Erlang, Akka или CAF,
сообщение отсылается не конкретному агенту
(актору), а в почтовый ящик (mbox).
SObjectizer Team, февраль 2015
Несколько слов о почтовых ящиках (mbox-ах)...
В SObjectizer, в отличии от похожих
инструментов, вроде Erlang, Akka или CAF,
сообщение отсылается не конкретному
агенту(актору), а в почтовый ящик (mbox).
За mbox-ом в SObjectizer-е может скрываться
как один агент, так и несколько агентов.
А может и ни одного.
SObjectizer Team, февраль 2015
В SObjectizer есть два типа mbox-ов:
SObjectizer Team, февраль 2015
В SObjectizer есть два типа mbox-ов:
Multi-Producers/Multi-Consumers mbox-ы.
Похожи на “доски объявлений”. Отосланное в
mbox сообщение становится доступным для всех,
кто подписан на этот mbox.
В примере выше продемонстрирован MPMC-mbox.
SObjectizer Team, февраль 2015
В SObjectizer есть два типа mbox-ов:
Multi-Producers/Multi-Consumers mbox-ы.
Похожи на “доски объявлений”. Отосланное в mbox
сообщение становится доступным для всех, кто
подписан на этот mbox.
В примере выше продемонстрирован MPMC-mbox.
Multi-Producers/Single-Consumer mbox-ы.
У этих mbox-ов только один подписчик - агент,
которому принадлежит MPSC-mbox.
SObjectizer Team, февраль 2015
Чтобы продемонстрировать особенности
MPMC-mbox-ов добавим в приведенный пример
еще одного агента...
SObjectizer Team, февраль 2015
Чтобы продемонстрировать особенности MPMC-
mbox-ов добавим в приведенный пример еще
одного агента...
Этот агент будет “слушать” обмен сообщениями
между агентами pinger и ponger, подсчитывая
количество пересланных сообщений.
SObjectizer Team, февраль 2015
Агент listener:
class listener : public so_5::rt::agent_t
{
public :
listener( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override {
so_default_state()
.event( m_table, [this]( const ping & ) { ++m_pings; } )
.event( m_table, [this]( const pong & ) { ++m_pongs; } );
}
virtual void so_evt_finish() override {
std::cout << "result: " << m_pings << "/" << m_pongs << std::endl;
}
private :
const so_5::rt::mbox_t m_table;
unsigned int m_pings = 0;
unsigned int m_pongs = 0;
};
SObjectizer Team, февраль 2015
Агент listener:
class listener : public so_5::rt::agent_t
{
public :
listener( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override {
so_default_state()
.event( m_table, [this]( const ping & ) { ++m_pings; } )
.event( m_table, [this]( const pong & ) { ++m_pongs; } );
}
virtual void so_evt_finish() override {
std::cout << "result: " << m_pings << "/" << m_pongs << std::endl;
}
private :
const so_5::rt::mbox_t m_table;
unsigned int m_pings = 0;
unsigned int m_pongs = 0;
};
Агенту нужно получать два
сообщения. Поэтому он
подписывает два своих
события.
Вместо методов
обработчиков используются
лямбда-функции. Тип
сообщений, на которые
производится подписка,
выводится автоматически по
сигнатуре лямбда-функций.
SObjectizer Team, февраль 2015
Агент listener:
class listener : public so_5::rt::agent_t
{
public :
listener( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
, m_table( env.create_local_mbox( "table" ) )
{}
virtual void so_define_agent() override {
so_default_state()
.event( m_table, [this]( const ping & ) { ++m_pings; } )
.event( m_table, [this]( const pong & ) { ++m_pongs; } );
}
virtual void so_evt_finish() override {
std::cout << "result: " << m_pings << "/" << m_pongs << std::endl;
}
private :
const so_5::rt::mbox_t m_table;
unsigned int m_pings = 0;
unsigned int m_pongs = 0;
};
Метод so_evt_finish() является
противоположностью метода
so_evt_start().
Он вызывается у агента
непосредственно перед тем, как
агент завершит свою работу.
В данном случае этот метод
используется для выдачи
результатов.
SObjectizer Team, февраль 2015
Если теперь добавить listener-а в кооперацию:
SObjectizer Team, февраль 2015
Если теперь добавить listener-а в кооперацию:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
coop->add_agent( new listener( env ) );
env.register_coop( std::move( coop ) );
}
SObjectizer Team, февраль 2015
Если теперь добавить listener-а в кооперацию:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
coop->add_agent( new listener( env ) );
env.register_coop( std::move( coop ) );
}
То в конце своей работы пример напечатает:
result: 501/501
SObjectizer Team, февраль 2015
Если теперь добавить listener-а в кооперацию:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
coop->add_agent( new pinger( env ) );
coop->add_agent( new ponger( env ) );
coop->add_agent( new listener( env ) );
env.register_coop( std::move( coop ) );
}
То в конце своей работы пример напечатает:
result: 501/501
Т.е. отсылка сообщения в MPMC-mbox - это
широковещательная рассылка всем подписчикам.
SObjectizer Team, февраль 2015
В отличии от MPMC-mbox-а, который нужно
создавать вручную, MPSC-mbox-ы создаются
автоматически для каждого агента.
Т.е. у каждого агента есть свой собственный
MPSC-mbox, который называется direct_mbox-ом.
SObjectizer Team, февраль 2015
В отличии от MPMC-mbox-а, который нужно
создавать вручную, MPSC-mbox-ы создаются
автоматически для каждого агента.
Т.е. у каждого агента есть свой собственный
MPSC-mbox, который называется direct_mbox-ом.
Отправленное в MPSC-mbox сообщение либо
отдается владельцу mbox-а на обработку, либо
выбрасывается, если владелец на сообщение не
подписан.
SObjectizer Team, февраль 2015
В отличии от MPMC-mbox-а, который нужно создавать
вручную, MPSC-mbox-ы создаются автоматически для
каждого агента.
Т.е. у каждого агента есть свой собственный MPSC-mbox,
который называется direct_mbox-ом.
Отправленное в MPSC-mbox сообщение либо
отдается владельцу mbox-а на обработку, либо
выбрасывается, если владелец на сообщение не
подписан.
Т.е. если два агента общаются друг с другом
через direct_mbox-ы, то никто не может
“прослушать” их общение.
SObjectizer Team, февраль 2015
Однако, смысл существования direct_mbox-ов
вовсе не в том, чтобы позволить двум агентам
установить “закрытый канал” общения.
SObjectizer Team, февраль 2015
Однако, смысл существования direct_mbox-ов
вовсе не в том, чтобы позволить двум агентам
установить “закрытый канал” общения.
Direct_mbox-ы заметно эффективнее MPMC-
mbox-ов, т.к. диспетчеризация сообщений для
direct_mbox-ов гораздо проще и требует меньше
внутренних блокировок.
SObjectizer Team, февраль 2015
Однако, смысл существования direct_mbox-ов
вовсе не в том, чтобы позволить двум агентам
установить “закрытый канал” общения.
Direct_mbox-ы заметно эффективнее MPMC-mbox-
ов, т.к. диспетчеризация сообщений для
direct_mbox-ов гораздо проще и требует меньше
внутренних блокировок.
Поэтому, если прикладной логике не требуется
широковещательный обмен сообщениями, то
лучше работать посредством direct_mbox-ов.
SObjectizer Team, февраль 2015
В обсуждавшемся выше примере с двумя
агентами pinger и ponger широковещательная
рассылка не нужна.
SObjectizer Team, февраль 2015
В обсуждавшемся выше примере с двумя
агентами pinger и ponger широковещательная
рассылка не нужна.
Поэтому переделаем этот пример под работу с
direct_mbox-ами.
SObjectizer Team, февраль 2015
В обсуждавшемся выше примере с двумя
агентами pinger и ponger широковещательная
рассылка не нужна.
Поэтому переделаем этот пример под работу с
direct_mbox-ами.
Заодно и выбросив агента listener-а.
Пусть pinger и ponger сами ведут подсчет
SObjectizer Team, февраль 2015
В обсуждавшемся выше примере с двумя
агентами pinger и ponger широковещательная
рассылка не нужна.
Поэтому переделаем этот пример под работу с
direct_mbox-ами.
Заодно и выбросив агента listener-а.
Пусть pinger и ponger сами ведут подсчет
Ну и поменяв сообщения на сигналы
SObjectizer Team, февраль 2015
Сигналы - это разновидность сообщений, в
которых есть лишь факт существования
сообщения.
Но нет никаких данных внутри сообщения.
SObjectizer Team, февраль 2015
Сигналы - это разновидность сообщений, в
которых есть лишь факт существования
сообщения.
Но нет никаких данных внутри сообщения.
Это очень напоминает пересылку
атомов в Erlang, когда отсылается
только атом, без какой-либо
дополнительной информации.
SObjectizer Team, февраль 2015
При использовании SObjectizer сигналы
оказались настолько распространены, что для их
поддержки добавлены специальные механизмы.
SObjectizer Team, февраль 2015
При использовании SObjectizer сигналы
оказались настолько распространены, что для их
поддержки добавлены специальные механизмы.
На уровне API работа с сигналами в чем-то
похожа на работу с сообщениями. В чем-то нет.
SObjectizer Team, февраль 2015
Меняем сообщения ping и pong на сигналы...
SObjectizer Team, февраль 2015
Меняем сообщения ping и pong на сигналы...
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
struct ping : public so_5::rt::signal_t {};
struct pong : public so_5::rt::signal_t {};
SObjectizer Team, февраль 2015
Меняем сообщения ping и pong на сигналы...
Сигналы должны наследоваться от
so_5::rt::signal_t и не должны содержать данных.
struct ping : public so_5::rt::message_t
{
unsigned int m_req;
ping( unsigned int req ) : m_req{ req } {}
};
struct pong : public so_5::rt::message_t
{
unsigned int m_resp;
pong( unsigned int resp ) : m_resp{ resp } {}
};
struct ping : public so_5::rt::signal_t {};
struct pong : public so_5::rt::signal_t {};
SObjectizer Team, февраль 2015
Меняем агента pinger-а...
SObjectizer Team, февраль 2015
Меняем агента pinger-а (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) {
m_ponger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< pong >(
[this]{
++m_pongs;
so_5::send< ping >( m_ponger );
} );
}
SObjectizer Team, февраль 2015
Меняем агента pinger-а (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) {
m_ponger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< pong >(
[this]{
++m_pongs;
so_5::send< ping >( m_ponger );
} );
}
direct_mbox становится доступен
только после создания агента.
Поэтому для связывания pinger-а
и ponger-а потребовался
отдельный метод, который будет
вызываться после создания
обоих агентов.
SObjectizer Team, февраль 2015
Меняем агента pinger-а (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) {
m_ponger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< pong >(
[this]{
++m_pongs;
so_5::send< ping >( m_ponger );
} );
}
В метод event() передается всего
один аргумент: лямбда-функция
с обработчиком сигнала. В этом
случае event() делает подписку
на сигнал, поступающий от
direct_mbox-а агента.
SObjectizer Team, февраль 2015
Меняем агента pinger-а (начало):
class pinger : public so_5::rt::agent_t
{
public :
pinger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) {
m_ponger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< pong >(
[this]{
++m_pongs;
so_5::send< ping >( m_ponger );
} );
}
При подписке на сигнал нужно
явно указывать тип сигнала.
Обработчиком сигнала должен
быть метод или лямбда-функция
без параметров.
В отличии от сообщения, нет
экземпляра сигнала, поэтому
нечего передавать параметром
обработчику события.
SObjectizer Team, февраль 2015
Меняем агента pinger-а (окончание):
virtual void so_evt_start() override {
so_5::send< ping >( m_ponger );
}
virtual void so_evt_finish() override {
std::cout << "pongs: " << m_pongs << std::endl;
}
private :
so_5::rt::mbox_t m_ponger;
unsigned int m_pongs = 0;
};
SObjectizer Team, февраль 2015
Меняем агента pinger-а (окончание):
virtual void so_evt_start() override {
so_5::send< ping >( m_ponger );
}
virtual void so_evt_finish() override {
std::cout << "pongs: " << m_pongs << std::endl;
}
private :
so_5::rt::mbox_t m_ponger;
unsigned int m_pongs = 0;
};
Отсылка сигнала выполняется
той же функцией so_5::send(), что
и отсылка сообщения.
Но после mbox-а получателя
больше никаких аргументов не
требуется.
SObjectizer Team, февраль 2015
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) {
m_pinger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< ping >(
[this]{
++m_pings;
so_5::send< pong >( m_pinger );
} );
}
Аналогичным образом меняется агент ponger (начало):
SObjectizer Team, февраль 2015
virtual void so_evt_finish() override {
std::cout << "pings: " << m_pings << std::endl;
}
private :
so_5::rt::mbox_t m_pinger;
unsigned int m_pings = 0;
};
Аналогичным образом меняется агент ponger (окончание):
SObjectizer Team, февраль 2015
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
env.register_coop( std::move( coop ) );
}
Создание кооперации становится более многословным:
SObjectizer Team, февраль 2015
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
env.register_coop( std::move( coop ) );
}
Создание кооперации становится более многословным:
Кроме того, здесь есть ошибка...
SObjectizer Team, февраль 2015
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
env.register_coop( std::move( coop ) );
}
Создание кооперации становится более многословным:
Кроме того, здесь есть ошибка...
Никто не остановит этих агентов!
Они будут пинговать друг друга постоянно.
SObjectizer Team, февраль 2015
Исправим проблему, добавив еще одного
агента, который завершит работу примера через
одну секунду...
SObjectizer Team, февраль 2015
Исправим проблему, добавив еще одного агента,
который завершит работу примера через одну
секунду...
Поскольку агент будет обрабатывать всего одно
событие, нет смысла определять отдельный
класс для этого агента, переопределять в нем
метод so_define_agent() и т.д.
SObjectizer Team, февраль 2015
Исправим проблему, добавив еще одного агента,
который завершит работу примера через одну
секунду...
Поскольку агент будет обрабатывать всего одно
событие, нет смысла определять отдельный
класс для этого агента, переопределять в нем
метод so_define_agent() и т.д.
Вместо этого создадим ad-hoc-агента.
Т.е. агента, описанного “по месту”, без
дополнительных формальностей.
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
Сигнал на завершение работы.
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
Создание ad-hoc-агента.
Возвращается дескриптор, через
который агента можно
настраивать.
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
Новый агент подписывается на
единственный сигнал stop.
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
Сигнал придет на direct_mbox
нового агента.
SObjectizer Team, февраль 2015
Ad-hoc-агент для завершения примера через
секунду после начала работы:
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
Обработчик этого сигнала даст
приказ SObjectizer Environment
завершить работу примера.
Единственная кооперация будет
дерегистрирована
автоматически.
SObjectizer Team, февраль 2015
Ad-hoc-агент создан и настроен.
Осталось отослать отложенный на одну секунду
сигнал stop:
SObjectizer Team, февраль 2015
Ad-hoc-агент создан и настроен.
Осталось отослать отложенный на одну секунду
сигнал stop:
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
SObjectizer Team, февраль 2015
Ad-hoc-агент создан и настроен.
Осталось отослать отложенный на одну секунду
сигнал stop:
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
Функция so_5::send_delayed
отсылает отложенное на
указанное время сообщение или
сигнал.
В данном случае сигнал stop на
direct_mbox нового ad-hoc-агента
через одну секунду.
SObjectizer Team, февраль 2015
В итоге стартовая функция приняла вид:
void init( so_5::rt::environment_t & env )
{
auto coop = env.create_coop( so_5::autoname );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent();
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
SObjectizer Team, февраль 2015
Запускаем обновленный пример...
SObjectizer Team, февраль 2015
Запускаем обновленный пример...
Получаем...
pongs: 4441168
pings: 4441169
SObjectizer Team, февраль 2015
Запускаем обновленный пример...
Получаем...
pongs: 4441168
pings: 4441169
Итого больше 8M сообщений в секунду.
SObjectizer Team, февраль 2015
Итого больше 8M сообщений в секунду
Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit,
Visual C++ 2013 64-bit
Запускаем обновленный пример...
Получаем...
pongs: 4441168
pings: 4441169
SObjectizer Team, февраль 2015
Итого больше 8M сообщений в секунду
Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit,
Visual C++ 2013 64-bit
Запускаем обновленный пример...
Получаем...
pongs: 4441168
pings: 4441169
Это хорошо, но на каком контексте работают
агенты в данном примере?
SObjectizer Team, февраль 2015
Все агенты работают на одной общей рабочей нити!
SObjectizer Team, февраль 2015
Все агенты работают на одной общей рабочей нити!
Т.е. никакой многопоточности пока не видно. Пример
показал лишь возможности по передаче сообщений
между агентами, разделяющими общий рабочий
контекст.
SObjectizer Team, февраль 2015
Все агенты работают на одной общей рабочей нити!
Т.е. никакой многопоточности пока не видно. Пример
показал лишь возможности по передачи сообщений
между агентами, разделяющими общий рабочий
контекст.
Но кто выбирает рабочий контекст для агентов?
И как привязать агента к другому контексту?
SObjectizer Team, февраль 2015
Все агенты работают на одной общей рабочей нити!
Т.е. никакой многопоточности пока не видно. Пример
показал лишь возможности по передачи сообщений
между агентами, разделяющими общий рабочий
контекст.
Но кто выбирает рабочий контекст для агентов?
И как привязать агента к другому контексту?
Контекст выбирает программист, указывая, на каком
диспетчере должен работать агент.
Если диспетчер не указан, то агент привязывается к
диспетчеру по умолчанию.
SObjectizer Team, февраль 2015
Все агенты работают на одной общей рабочей нити!
Т.е. никакой многопоточности пока не видно. Пример
показал лишь возможности по передачи сообщений
между агентами, разделяющими общий рабочий
контекст.
Но кто выбирает рабочий контекст для агентов?
И как привязать агента к другому контексту?
Контекст выбирает программист, указывая, на каком
диспетчере должен работать агент.
Если диспетчер не указан, то агент привязывается к
диспетчеру по умолчанию.
Как это и произошло в данном примере.
SObjectizer Team, февраль 2015
Диспетчер по умолчанию запускает события всех
своих агентов на одной общей рабочей нити.
Для этих агентов получается что-то вроде
кооперативной многозадачности. Если кто-то стал
“тормозить”, то “тормозить” начинают и остальные.
SObjectizer Team, февраль 2015
Диспетчер по умолчанию запускает события всех своих
агентов на одной общей рабочей нити.
Для этих агентов получается что-то вроде
кооперативной многозадачности. Если кто-то стал
“тормозить”, то “тормозить” начинают и остальные.
Но можно создать произвольное количество
необходимых приложению диспетчеров и
привязать своих агентов к этим диспетчерам.
SObjectizer Team, февраль 2015
Заставим агентов pinger и ponger работать на
разных рабочих нитях (чтобы у каждого из них
была своя собственная рабочая нить)...
SObjectizer Team, февраль 2015
Заставим агентов pinger и ponger работать на
разных рабочих нитях (чтобы у каждого из них
была своя собственная рабочая нить)...
Для этого создадим диспетчера active_obj и
привяжем агентов к нему.
SObjectizer Team, февраль 2015
Заставим агентов pinger и ponger работать на
разных рабочих нитях (чтобы у каждого из них
была своя собственная рабочая нить)...
Для этого создадим диспетчера active_obj и
привяжем агентов к нему.
Данный диспетчер каждому своему агенту
выделяет отдельную рабочую нить (агент
оказывается активным объектом).
SObjectizer Team, февраль 2015
Для этого ничего не нужно менять в агентах...
SObjectizer Team, февраль 2015
Для этого ничего не нужно менять в агентах...
Изменения затронут только стартовую функцию.
SObjectizer Team, февраль 2015
Привязка агентов к разным диспетчерам:
void init( so_5::rt::environment_t & env )
{
env.add_dispatcher_if_not_exists(
"active_obj",
&so_5::disp::active_obj::create_disp );
auto coop = env.create_coop( so_5::autoname,
so_5::disp::active_obj::create_disp_binder("active_obj") );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() );
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
SObjectizer Team, февраль 2015
Привязка агентов к разным диспетчерам:
void init( so_5::rt::environment_t & env )
{
env.add_dispatcher_if_not_exists(
"active_obj",
&so_5::disp::active_obj::create_disp );
auto coop = env.create_coop( so_5::autoname,
so_5::disp::active_obj::create_disp_binder("active_obj") );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() );
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
Просьба создать
диспетчера с активными
объектами под именем
“active_obj”. Если такого
диспетчера еще нет, то он
будет создан с помощью
указанной фабрики.
SObjectizer Team, февраль 2015
Привязка агентов к разным диспетчерам:
void init( so_5::rt::environment_t & env )
{
env.add_dispatcher_if_not_exists(
"active_obj",
&so_5::disp::active_obj::create_disp );
auto coop = env.create_coop( so_5::autoname,
so_5::disp::active_obj::create_disp_binder("active_obj") );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() );
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
Указание кооперации о том,
что основным диспетчером
для ее агентов будет
диспетчер с именем
“active_obj”.
SObjectizer Team, февраль 2015
Привязка агентов к разным диспетчерам:
void init( so_5::rt::environment_t & env )
{
env.add_dispatcher_if_not_exists(
"active_obj",
&so_5::disp::active_obj::create_disp );
auto coop = env.create_coop( so_5::autoname,
so_5::disp::active_obj::create_disp_binder("active_obj") );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() );
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
Агенты pinger и ponger
добавляются в
кооперацию без каких-
либо дополнительных
инструкций. Значит они
будут привязаны к тому
диспетчеру, который для
кооперации считается
основным диспетчером. В
данном случае это будет
диспетчер с именем
“active_obj”.
SObjectizer Team, февраль 2015
Привязка агентов к разным диспетчерам:
void init( so_5::rt::environment_t & env )
{
env.add_dispatcher_if_not_exists(
"active_obj",
&so_5::disp::active_obj::create_disp );
auto coop = env.create_coop( so_5::autoname,
so_5::disp::active_obj::create_disp_binder("active_obj") );
auto a_pinger = coop->add_agent( new pinger( env ) );
auto a_ponger = coop->add_agent( new ponger( env ) );
a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() );
a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() );
struct stop : public so_5::rt::signal_t {};
auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() );
stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
env.register_coop( std::move( coop ) );
so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
}
А вот для агента stopper-а отдельная
рабочая нить не нужна. Поэтому этот
объект явным образом привязывается к
диспетчеру SObjectizer по умолчанию.
Если такого прямого указания не
сделать, то для агента будет выполнена
привязка к основному диспетчеру
кооперации.
SObjectizer Team, февраль 2015
Что получается после запуска обновленного примера?
SObjectizer Team, февраль 2015
Что получается после запуска обновленного примера?
pings: pongs: 1234623
1234624
SObjectizer Team, февраль 2015
Что получается после запуска обновленного примера?
pings: pongs: 1234623
1234624
Упс… Или так и должно быть?
SObjectizer Team, февраль 2015
Что получается после запуска обновленного примера?
pings: pongs: 1234623
1234624
Упс… Или так и должно быть?
Это, действительно упс. Но так и должно быть
SObjectizer Team, февраль 2015
Что получается после запуска обновленного примера?
pings: pongs: 1234623
1234624
Упс… Или так и должно быть?
Это, действительно упс. Но так и должно быть
Могло бы быть и еще страшнее
SObjectizer Team, февраль 2015
Что же произошло?
pings: pongs: 1234623
1234624
SObjectizer Team, февраль 2015
Что же произошло?
pings: pongs: 1234623
1234624
Агенты pinger и ponger стали работать на
разных нитях и конкурировать за доступ к std::
cout. В результате этой конкуренции вывод в
std::cout перемешался. Мог бы перемешаться
еще больше. А мог бы и не перемешаться
вовсе. Многопоточность…
SObjectizer Team, февраль 2015
Что еще произошло?
pings: pongs: 1234623
1234624
SObjectizer Team, февраль 2015
Что еще произошло?
pings: pongs: 1234623
1234624
Упала общая производительность примера.
Если на одной нити был показан результат в
8M сообщений в секунду, то на двух нитях -
всего 2M сообщений.
SObjectizer Team, февраль 2015
Что еще произошло?
pings: pongs: 1234623
1234624
Упала общая производительность примера.
Если на одной нити был показан результат в
8M сообщений в секунду, то на двух нитях -
всего 2M сообщений.
Что вполне ожидаемо, т.к. передача единичных
сообщений с одной нити на другую - это
дорогостоящая операция.
SObjectizer Team, февраль 2015
Но что изменилось в самих агентах?
SObjectizer Team, февраль 2015
Но что изменилось в самих агентах?
Ничего.
SObjectizer Team, февраль 2015
Агент ponger для
одной рабочей нити:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) {
m_pinger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< ping >(
[this]{
++m_pings;
so_5::send< pong >( m_pinger );
} );
}
virtual void so_evt_finish() override {
std::cout << "pings: " << m_pings << std::endl;
}
private :
so_5::rt::mbox_t m_pinger;
unsigned int m_pings = 0;
};
SObjectizer Team, февраль 2015
Агент ponger для
одной рабочей нити:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) {
m_pinger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< ping >(
[this]{
++m_pings;
so_5::send< pong >( m_pinger );
} );
}
virtual void so_evt_finish() override {
std::cout << "pings: " << m_pings << std::endl;
}
private :
so_5::rt::mbox_t m_pinger;
unsigned int m_pings = 0;
};
Агент ponger для
двух рабочих нитей:
class ponger : public so_5::rt::agent_t
{
public :
ponger( so_5::rt::environment_t & env )
: so_5::rt::agent_t( env )
{}
void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) {
m_pinger = mbox;
}
virtual void so_define_agent() override {
so_default_state().event< ping >(
[this]{
++m_pings;
so_5::send< pong >( m_pinger );
} );
}
virtual void so_evt_finish() override {
std::cout << "pings: " << m_pings << std::endl;
}
private :
so_5::rt::mbox_t m_pinger;
unsigned int m_pings = 0;
};
SObjectizer Team, февраль 2015
Это прямое следствие того, что агенты
взаимодействовали друг с другом только
посредством асинхронных сообщений.
SObjectizer Team, февраль 2015
Это прямое следствие того, что агенты
взаимодействовали друг с другом только
посредством асинхронных сообщений.
Поэтому им все равно, на каком контексте они
работают.
SObjectizer Team, февраль 2015
Это прямое следствие того, что агенты
взаимодействовали друг с другом только
посредством асинхронных сообщений.
Поэтому им все равно, на каком контексте они
работают.
А задачей SObjectizer-а является
предоставление программисту возможности
выбрать нужный ему контекст путем
привязки агентов к соответствующим
диспетчерам.
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
● one_thread. Запускает всех агентов на одной общей рабочей нити;
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
● one_thread. Запускает всех агентов на одной общей рабочей нити;
● active_obj. Предоставляет каждому агенту отдельную нить в
единоличное пользование;
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
● one_thread. Запускает всех агентов на одной общей рабочей нити;
● active_obj. Предоставляет каждому агенту отдельную нить в
единоличное пользование;
● active_group. Предоставляет отдельную нить в единоличное
пользование группе объектов;
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
● one_thread. Запускает всех агентов на одной общей рабочей нити;
● active_obj. Предоставляет каждому агенту отдельную нить в
единоличное пользование;
● active_group. Предоставляет отдельную нить в единоличное
пользование группе объектов;
● thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты
могут мигрировать с одной рабочей нити на другую. Но агент не
может работать на двух рабочих нитях одновременно;
SObjectizer Team, февраль 2015
Для этого в SObjectizer есть целый ряд готовых
диспетчеров “из коробки”:
● one_thread. Запускает всех агентов на одной общей рабочей нити;
● active_obj. Предоставляет каждому агенту отдельную нить в
единоличное пользование;
● active_group. Предоставляет отдельную нить в единоличное
пользование группе объектов;
● thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты
могут мигрировать с одной рабочей нити на другую. Но агент не
может работать на двух рабочих нитях одновременно;
● adv_thread_pool. Выделяет агентам нити из пула рабочих нитей.
Агенты могут и мигрировать с одной рабочей нити на другую, и
работать сразу на нескольких (при условии, что их обработчики
событий объявлены thread safe).
SObjectizer Team, февраль 2015
При этом разработчик может не только
выбирать нужный ему тип диспетчера...
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное
ему количество нужных ему типов диспетчеров.
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное ему
количество нужных ему типов диспетчеров.
Например:
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное ему
количество нужных ему типов диспетчеров.
Например:
● один one_thread диспетчер для агента-клиента AMQP;
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное ему
количество нужных ему типов диспетчеров.
Например:
● один one_thread диспетчер для агента-клиента AMQP;
● один thread_pool диспетчер для обработки прочитанных из AMQP-
очередей запросов;
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное ему
количество нужных ему типов диспетчеров.
Например:
● один one_thread диспетчер для агента-клиента AMQP;
● один thread_pool диспетчер для обработки прочитанных из AMQP-
очередей запросов;
● один active_obj диспетчер для агентов, выполняющих работу с СУБД;
SObjectizer Team, февраль 2015
При этом разработчик может не только выбирать
нужный ему тип диспетчера...
...Но и создавать в своем приложении нужное ему
количество нужных ему типов диспетчеров.
Например:
● один one_thread диспетчер для агента-клиента AMQP;
● один thread_pool диспетчер для обработки прочитанных из AMQP-
очередей запросов;
● один active_obj диспетчер для агентов, выполняющих работу с СУБД;
● еще один active_obj диспетчер для агентов, работающих с
подключенными к компьютеру HSM-ами;
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть
Погружение в SObjectizer 5.5. Вводная часть

More Related Content

What's hot

Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программированиеDenis Tsvettsih
 
Релиз PHP7 - что нас ждет в октябре 2015
Релиз PHP7 - что нас ждет в октябре 2015Релиз PHP7 - что нас ждет в октябре 2015
Релиз PHP7 - что нас ждет в октябре 2015Andrey Tokarchuk
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model LibraryAndrey Gordienkov
 
C# Web. Занятие 02.
C# Web. Занятие 02.C# Web. Занятие 02.
C# Web. Занятие 02.Igor Shkulipa
 
VAMR ACADEMY Второе занятие
VAMR ACADEMY Второе занятиеVAMR ACADEMY Второе занятие
VAMR ACADEMY Второе занятиеmixARConference
 
Разработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешевоРазработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешевоDotNetConf
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.Igor Shkulipa
 
C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.Igor Shkulipa
 
Как это будет: ASP.NET Core
Как это будет: ASP.NET CoreКак это будет: ASP.NET Core
Как это будет: ASP.NET CoreDotNetConf
 
C++ Базовый. Занятие 13.
C++ Базовый. Занятие 13.C++ Базовый. Занятие 13.
C++ Базовый. Занятие 13.Igor Shkulipa
 
Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программированиеDotNetConf
 
введение в Javascript
введение в Javascriptвведение в Javascript
введение в Javascriptinqubick
 
Константин Васильев «Fody против рутины»
Константин Васильев «Fody против рутины»Константин Васильев «Fody против рутины»
Константин Васильев «Fody против рутины»SpbDotNet Community
 
Григорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыГригорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыYandex
 

What's hot (20)

Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программирование
 
Релиз PHP7 - что нас ждет в октябре 2015
Релиз PHP7 - что нас ждет в октябре 2015Релиз PHP7 - что нас ждет в октябре 2015
Релиз PHP7 - что нас ждет в октябре 2015
 
PostSharp - Threading Model Library
PostSharp - Threading Model LibraryPostSharp - Threading Model Library
PostSharp - Threading Model Library
 
PostSharp - Threading Model
PostSharp - Threading ModelPostSharp - Threading Model
PostSharp - Threading Model
 
C# Web. Занятие 02.
C# Web. Занятие 02.C# Web. Занятие 02.
C# Web. Занятие 02.
 
VAMR ACADEMY Второе занятие
VAMR ACADEMY Второе занятиеVAMR ACADEMY Второе занятие
VAMR ACADEMY Второе занятие
 
Step 7
Step 7Step 7
Step 7
 
Разработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешевоРазработка надежных параллельных, распределенных приложений: быстро и дешево
Разработка надежных параллельных, распределенных приложений: быстро и дешево
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.
 
C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.C++ STL & Qt. Занятие 11.
C++ STL & Qt. Занятие 11.
 
Как это будет: ASP.NET Core
Как это будет: ASP.NET CoreКак это будет: ASP.NET Core
Как это будет: ASP.NET Core
 
C++ Базовый. Занятие 13.
C++ Базовый. Занятие 13.C++ Базовый. Занятие 13.
C++ Базовый. Занятие 13.
 
лекция 5
лекция 5лекция 5
лекция 5
 
лек11 4
лек11 4лек11 4
лек11 4
 
Как приручить реактивное программирование
Как приручить реактивное программированиеКак приручить реактивное программирование
Как приручить реактивное программирование
 
Step 1
Step 1Step 1
Step 1
 
введение в Javascript
введение в Javascriptвведение в Javascript
введение в Javascript
 
Константин Васильев «Fody против рутины»
Константин Васильев «Fody против рутины»Константин Васильев «Fody против рутины»
Константин Васильев «Fody против рутины»
 
Григорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыГригорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммы
 
Цена ошибки
Цена ошибкиЦена ошибки
Цена ошибки
 

Similar to Погружение в SObjectizer 5.5. Вводная часть

Изменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистовИзменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистовTatyanazaxarova
 
Distributed Development Practice
Distributed Development PracticeDistributed Development Practice
Distributed Development PracticeAlexander Veremyev
 
Remote (dev)tools своими руками
Remote (dev)tools своими рукамиRemote (dev)tools своими руками
Remote (dev)tools своими рукамиRoman Dvornov
 
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplantit-people
 
Внедрение компонента templating в существующий проект
Внедрение компонента templating в существующий проектВнедрение компонента templating в существующий проект
Внедрение компонента templating в существующий проектStanislaw Smetanin
 
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...SQALab
 
UAFPUG6 - PureMVC
UAFPUG6 - PureMVCUAFPUG6 - PureMVC
UAFPUG6 - PureMVCmandrew182
 
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryUafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryMax Rozdobudko
 
Александр Белоцерковский "Microsoft Bot Framework" - EdHack
Александр Белоцерковский "Microsoft Bot Framework" - EdHackАлександр Белоцерковский "Microsoft Bot Framework" - EdHack
Александр Белоцерковский "Microsoft Bot Framework" - EdHackchatbotscommunity
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Anthony Marchenko
 
Разработка веб-приложений с помощью TypeScript
Разработка веб-приложений с помощью TypeScriptРазработка веб-приложений с помощью TypeScript
Разработка веб-приложений с помощью TypeScriptStas Vyschepan
 
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...COMAQA.BY
 
Py con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circlePy con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circleRostislav Bryzgunov
 
MockServer-driven development
MockServer-driven developmentMockServer-driven development
MockServer-driven developmentTestableapple
 
Иван Васильев
Иван ВасильевИван Васильев
Иван ВасильевCodeFest
 
Как мы тестируем анализатор кода
Как мы тестируем анализатор кодаКак мы тестируем анализатор кода
Как мы тестируем анализатор кодаTatyanazaxarova
 
C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.Igor Shkulipa
 

Similar to Погружение в SObjectizer 5.5. Вводная часть (20)

Изменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистовИзменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистов
 
Distributed Development Practice
Distributed Development PracticeDistributed Development Practice
Distributed Development Practice
 
Remote (dev)tools своими руками
Remote (dev)tools своими рукамиRemote (dev)tools своими руками
Remote (dev)tools своими руками
 
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
"Портирование Web SDK с JS на TS" Петров Григорий, Voximplant
 
Внедрение компонента templating в существующий проект
Внедрение компонента templating в существующий проектВнедрение компонента templating в существующий проект
Внедрение компонента templating в существующий проект
 
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...
Monkey Talk - кросс-платформенное средство автоматизации тестирования мобильн...
 
UAFPUG6 - PureMVC
UAFPUG6 - PureMVCUAFPUG6 - PureMVC
UAFPUG6 - PureMVC
 
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryUafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
 
PureMVC and Papervision
PureMVC and PapervisionPureMVC and Papervision
PureMVC and Papervision
 
Александр Белоцерковский "Microsoft Bot Framework" - EdHack
Александр Белоцерковский "Microsoft Bot Framework" - EdHackАлександр Белоцерковский "Microsoft Bot Framework" - EdHack
Александр Белоцерковский "Microsoft Bot Framework" - EdHack
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
 
Разработка веб-приложений с помощью TypeScript
Разработка веб-приложений с помощью TypeScriptРазработка веб-приложений с помощью TypeScript
Разработка веб-приложений с помощью TypeScript
 
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...
Владислав Акулич - Monkey Talk - кроссплатформенное средство автоматизации те...
 
Py con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circlePy con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circle
 
MockServer-driven development
MockServer-driven developmentMockServer-driven development
MockServer-driven development
 
DevOps guide for awesome quality assurance
DevOps guide for awesome quality assuranceDevOps guide for awesome quality assurance
DevOps guide for awesome quality assurance
 
Иван Васильев
Иван ВасильевИван Васильев
Иван Васильев
 
Как мы тестируем анализатор кода
Как мы тестируем анализатор кодаКак мы тестируем анализатор кода
Как мы тестируем анализатор кода
 
C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.C++ Базовый. Занятие 01.
C++ Базовый. Занятие 01.
 
335
335335
335
 

More from Yauheni Akhotnikau

arataga. SObjectizer and RESTinio in action: a real-world example
arataga. SObjectizer and RESTinio in action: a real-world examplearataga. SObjectizer and RESTinio in action: a real-world example
arataga. SObjectizer and RESTinio in action: a real-world exampleYauheni Akhotnikau
 
Actor Model and C++: what, why and how? (March 2020 Edition)
Actor Model and C++: what, why and how? (March 2020 Edition)Actor Model and C++: what, why and how? (March 2020 Edition)
Actor Model and C++: what, why and how? (March 2020 Edition)Yauheni Akhotnikau
 
What is SObjectizer 5.7 (at v.5.7.0)
What is SObjectizer 5.7 (at v.5.7.0)What is SObjectizer 5.7 (at v.5.7.0)
What is SObjectizer 5.7 (at v.5.7.0)Yauheni Akhotnikau
 
What is SObjectizer 5.6 (at v.5.6.0)
What is SObjectizer 5.6 (at v.5.6.0)What is SObjectizer 5.6 (at v.5.6.0)
What is SObjectizer 5.6 (at v.5.6.0)Yauheni Akhotnikau
 
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...Yauheni Akhotnikau
 
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...Yauheni Akhotnikau
 
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Yauheni Akhotnikau
 
Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Yauheni Akhotnikau
 
25 Years of C++ History Flashed in Front of My Eyes
25 Years of C++ History Flashed in Front of My Eyes25 Years of C++ History Flashed in Front of My Eyes
25 Years of C++ History Flashed in Front of My EyesYauheni Akhotnikau
 
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allGECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allYauheni Akhotnikau
 
Dive into SObjectizer 5.5. Tenth part: Mutable Messages
Dive into SObjectizer 5.5. Tenth part: Mutable MessagesDive into SObjectizer 5.5. Tenth part: Mutable Messages
Dive into SObjectizer 5.5. Tenth part: Mutable MessagesYauheni Akhotnikau
 
Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?Yauheni Akhotnikau
 
Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++Yauheni Akhotnikau
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Yauheni Akhotnikau
 
Dive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Ninth Part: Message ChainsDive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Ninth Part: Message ChainsYauheni Akhotnikau
 
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
Dive into SObjectizer 5.5. Eighth Part: DispatchersDive into SObjectizer 5.5. Eighth Part: Dispatchers
Dive into SObjectizer 5.5. Eighth Part: DispatchersYauheni Akhotnikau
 
What's new in SObjectizer 5.5.9
What's new in SObjectizer 5.5.9What's new in SObjectizer 5.5.9
What's new in SObjectizer 5.5.9Yauheni Akhotnikau
 
Dive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Seventh part: Message LimitsDive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Seventh part: Message LimitsYauheni Akhotnikau
 
Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction
Dive into SObjectizer-5.5. Sixth part: Synchronous InteractionDive into SObjectizer-5.5. Sixth part: Synchronous Interaction
Dive into SObjectizer-5.5. Sixth part: Synchronous InteractionYauheni Akhotnikau
 

More from Yauheni Akhotnikau (20)

arataga. SObjectizer and RESTinio in action: a real-world example
arataga. SObjectizer and RESTinio in action: a real-world examplearataga. SObjectizer and RESTinio in action: a real-world example
arataga. SObjectizer and RESTinio in action: a real-world example
 
Actor Model and C++: what, why and how? (March 2020 Edition)
Actor Model and C++: what, why and how? (March 2020 Edition)Actor Model and C++: what, why and how? (March 2020 Edition)
Actor Model and C++: what, why and how? (March 2020 Edition)
 
What is SObjectizer 5.7 (at v.5.7.0)
What is SObjectizer 5.7 (at v.5.7.0)What is SObjectizer 5.7 (at v.5.7.0)
What is SObjectizer 5.7 (at v.5.7.0)
 
What is SObjectizer 5.6 (at v.5.6.0)
What is SObjectizer 5.6 (at v.5.6.0)What is SObjectizer 5.6 (at v.5.6.0)
What is SObjectizer 5.6 (at v.5.6.0)
 
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
[C++ CoreHard Autumn 2018] Actors vs CSP vs Task...
 
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
Shrimp: A Rather Practical Example Of Application Development With RESTinio a...
 
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
Акторы в C++: взгляд старого практикующего актородела (St. Petersburg C++ Use...
 
Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?Акторы на C++: стоило ли оно того?
Акторы на C++: стоило ли оно того?
 
25 Years of C++ History Flashed in Front of My Eyes
25 Years of C++ History Flashed in Front of My Eyes25 Years of C++ History Flashed in Front of My Eyes
25 Years of C++ History Flashed in Front of My Eyes
 
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them allGECon 2017: C++ - a Monster that no one likes but that will outlast them all
GECon 2017: C++ - a Monster that no one likes but that will outlast them all
 
Dive into SObjectizer 5.5. Tenth part: Mutable Messages
Dive into SObjectizer 5.5. Tenth part: Mutable MessagesDive into SObjectizer 5.5. Tenth part: Mutable Messages
Dive into SObjectizer 5.5. Tenth part: Mutable Messages
 
Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?Actor Model and C++: what, why and how?
Actor Model and C++: what, why and how?
 
Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++Шишки, набитые за 15 лет использования акторов в C++
Шишки, набитые за 15 лет использования акторов в C++
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?Модель акторов и C++ что, зачем и как?
Модель акторов и C++ что, зачем и как?
 
Dive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Ninth Part: Message ChainsDive into SObjectizer 5.5. Ninth Part: Message Chains
Dive into SObjectizer 5.5. Ninth Part: Message Chains
 
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
Dive into SObjectizer 5.5. Eighth Part: DispatchersDive into SObjectizer 5.5. Eighth Part: Dispatchers
Dive into SObjectizer 5.5. Eighth Part: Dispatchers
 
What's new in SObjectizer 5.5.9
What's new in SObjectizer 5.5.9What's new in SObjectizer 5.5.9
What's new in SObjectizer 5.5.9
 
Dive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Seventh part: Message LimitsDive into SObjectizer 5.5. Seventh part: Message Limits
Dive into SObjectizer 5.5. Seventh part: Message Limits
 
Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction
Dive into SObjectizer-5.5. Sixth part: Synchronous InteractionDive into SObjectizer-5.5. Sixth part: Synchronous Interaction
Dive into SObjectizer-5.5. Sixth part: Synchronous Interaction
 

Погружение в SObjectizer 5.5. Вводная часть

  • 1. Погружение в SObjectizer-5.5 SObjectizer Team, февраль 2015 Вводная часть
  • 2. SObjectizer Team, февраль 2015 О чем пойдет речь?
  • 3. О чем пойдет речь? Об инструменте для многопоточного программирования. SObjectizer Team, февраль 2015
  • 4. О чем пойдет речь? Об инструменте для многопоточного программирования. Которое считается сложным... SObjectizer Team, февраль 2015
  • 5. О чем пойдет речь? Об инструменте для многопоточного программирования. Которое считается сложным. Не просто сложным, SObjectizer Team, февраль 2015
  • 6. О чем пойдет речь? Об инструменте для многопоточного программирования Которое считается сложным. Не просто сложным, а ОЧЕНЬ СЛОЖНЫМ занятием. SObjectizer Team, февраль 2015
  • 7. Ведь постоянно иметь дело c низкоуровневыми примитивами вроде: SObjectizer Team, февраль 2015
  • 8. Ведь постоянно иметь дело c низкоуровневыми примитивами вроде: ● native threads ● critical sections, semaphores, mutexes, condition variables, monitors ● thread local storages ● atomic variables, spinlocks... SObjectizer Team, февраль 2015
  • 9. Ведь постоянно иметь дело с низкоуровневыми примитивами вроде: ● native threads ● critical sections, semaphores, mutexes, condition variables, monitors ● thread local storages ● atomic variables, spinlocks... И последствиями их применения в виде тупиков и гонок - это же очень сложно... SObjectizer Team, февраль 2015
  • 10. Ведь постоянно иметь дело c низкоуровневыми примитивами вроде: ● native threads ● critical sections, semaphores, mutexes, condition variables, monitors ● thread local storages ● atomic variables, spinlocks... И последствиями их применения в виде тупиков и гонок - это же очень сложно... Правильно? SObjectizer Team, февраль 2015
  • 13. SObjectizer Team, февраль 2015 Мы практически ни с чем из перечисленного не сталкиваемся
  • 14. SObjectizer позволяет организовать многопоточное приложение в виде совокупности объектов-агентов. SObjectizer Team, февраль 2015
  • 15. SObjectizer позволяет организовать многопоточное приложение в виде совокупности объектов-агентов. SObjectizer Team, февраль 2015 Взаимодействующих друг с другом только посредством асинхронных сообщений.
  • 16. Каждый агент получает свой собственный контекст, на котором выполняет обработку своих сообщений. SObjectizer Team, февраль 2015
  • 17. Каждый агент получает свой собственный контекст, на котором выполняет обработку своих сообщений. Агент привязан к своему контексту и может не заботиться о защите своих данных в многопоточном окружении. SObjectizer Team, февраль 2015
  • 18. Каждый агент получает свой собственный контекст, на котором выполняет обработку своих сообщений. Агент привязан к своему контексту и может не заботиться о защите своих данных в многопоточном окружении. Эта защита выполняется автоматически самим SObjectizer-ом! SObjectizer Team, февраль 2015
  • 20. Да! Это очень напоминает Actor Model SObjectizer Team, февраль 2015
  • 21. Да! Это очень напоминает Actor Model Потому что SObjectizer создавался и под ее влиянием... SObjectizer Team, февраль 2015
  • 22. Да! Это очень напоминает Actor Model Потому что SObjectizer создавался и под ее влиянием... При этом SObjectizer - это небольшая C++ библиотека, в зону ответственности которой входят: SObjectizer Team, февраль 2015
  • 23. Да! Это очень напоминает Actor Model Потому что SObjectizer создавался и под ее влиянием... При этом SObjectizer - это небольшая C++ библиотека, в зону ответственности которой входят: SObjectizer Team, февраль 2015 ● доставка сообщений внутри одного процесса и
  • 24. Да! Это очень напоминает Actor Model Потому что SObjectizer создавался и под ее влиянием... При этом SObjectizer - это небольшая C++ библиотека, в зону ответственности которой входят: SObjectizer Team, февраль 2015 ● доставка сообщений внутри одного процесса и ● предоставление рабочего контекста агентам, плюс
  • 25. Да! Это очень напоминает Actor Model Потому что SObjectizer создавался и под ее влиянием... При этом SObjectizer - это небольшая C++ библиотека, в зону ответственности которой входят: SObjectizer Team, февраль 2015 ● доставка сообщений внутри одного процесса и ● предоставление рабочего контекста агентам, плюс ● тонкая настройка всего этого дела
  • 26. SObjectizer Team, февраль 2015 У нас не было задачи создать еще один Erlang, со своим компилятором, стандартными библиотеками и средой исполнения
  • 27. SObjectizer вообще родился тогда, когда за пределами Ericsson о Erlang мало кто знал. SObjectizer Team, февраль 2015
  • 28. SObjectizer вообще родился тогда, когда за пределами Ericsson о Erlang мало кто знал. SObjectizer Team, февраль 2015 В 1996-м в Гомельском КБ Системного Программирования появилась первая версия SCADA Objectizer.
  • 29. SObjectizer вообще родился тогда, когда за пределами Ericsson о Erlang мало кто знал. SObjectizer Team, февраль 2015 В 1996-м в Гомельском КБ Системного Программирования появилась первая версия SCADA Objectizer. Это был инструмент для задач АСУ ТП, в котором агенты отсылали друг другу асинхронные сообщения.
  • 30. SObjectizer вообще родился тогда, когда за пределами Ericsson о Erlang мало кто знал. SObjectizer Team, февраль 2015 В 1996-м в Гомельском КБ Системного Программирования появилась первая версия SCADA Objectizer. Это был инструмент для задач АСУ ТП, в котором агенты отсылали друг другу асинхронные сообщения. А контекст для их обработки обеспечивался диспетчером.
  • 31. В 2000-м разработка SCADA Objectizer прекратилась, коллектив распался. Но идеи об агентах, обрабатывающих асинхронные сообщения под управлением диспетчера, - остались. SObjectizer Team, февраль 2015
  • 32. В 2000-м разработка SCADA Objectizer прекратилась, коллектив распался. Но идеи об агентах, обрабатывающих асинхронные сообщения под управлением диспетчера, - остались. SObjectizer Team, февраль 2015 Поэтому, когда в 2001-м уже в компании Интервэйл бывшие разработчики SCADA Objectizer реализовали многопоточное GUI- приложение, работающее с внешним оборудованием...
  • 33. SObjectizer Team, февраль 2015 ...то оказалось, что в нем живет примитивная и сильно урезанная версия SCADA Objectizer
  • 34. SObjectizer Team, февраль 2015 ...то оказалось, что в нем живет примитивная и сильно урезанная версия SCADA Objectizer Что дало толчок к разработке нового инструмента, построенного на тех же идеях, но уже имеющего новую реализацию...
  • 35. SObjectizer Team, февраль 2015 ...то оказалось, что в нем живет примитивная и сильно урезанная версия SCADA Objectizer Что дало толчок к разработке нового инструмента, построенного на тех же идеях, но уже имеющего новую реализацию... Так в 2002-м появился SObjectizer.
  • 36. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл.
  • 37. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем:
  • 38. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем: ● передачи SMS/USSD трафика;
  • 39. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем: ● передачи SMS/USSD трафика; ● обслуживания финансовых транзакций;
  • 40. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем: ● передачи SMS/USSD трафика; ● обслуживания финансовых транзакций; ● мониторинга параметров ПО.
  • 41. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем: ● передачи SMS/USSD трафика; ● обслуживания финансовых транзакций; ● мониторинга параметров ПО; В 2006-м открыт на SourceForge как OpenSource проект под BSD-лицензией.
  • 42. SObjectizer Team, февраль 2015 Долгое время SObjectizer был внутренним инструментом компании Интервэйл. Использовался в разработке систем: ● передачи SMS/USSD трафика; ● обслуживания финансовых транзакций; ● мониторинга параметров ПО. В 2006-м открыт на SourceForge как OpenSource проект под BSD-лицензией. С 2013-го развивается на SourceForge полностью как самостоятельный, независимый от Интервэйл проект.
  • 43. SObjectizer Team, февраль 2015 За время своего существования SObjectizer несколько раз полностью переписывался.
  • 44. SObjectizer Team, февраль 2015 За время своего существования SObjectizer несколько раз полностью переписывался. Далее речь пойдет о пятом поколении SObjectizer, разработка которого началась в 2010-м.
  • 45. SObjectizer Team, февраль 2015 За время своего существования SObjectizer несколько раз полностью переписывался. Далее речь пойдет о пятом поколении SObjectizer, разработка которого началась в 2010-м. А более конкретно - о версии 5.5.3, выпущенной в феврале 2015-го.
  • 46. SObjectizer Team, февраль 2015 Вся работа в SObjectizer происходит внутри SObjectizer Environment.
  • 47. SObjectizer Team, февраль 2015 Вся работа в SObjectizer происходит внутри SObjectizer Environment. SObjectizer Environment - это контейнер, содержащий SObjectizer Run-Time, кооперации агентов, почтовые ящики для обмена сообщениями, диспетчеры и таймерную нить.
  • 48. SObjectizer Team, февраль 2015 Вся работа в SObjectizer происходит внутри SObjectizer Environment. SObjectizer Environment - это контейнер, содержащий SObjectizer Run-Time, кооперации агентов, почтовые ящики для обмена сообщениями, диспетчеры и таймерную нить. Можно создать несколько экземпляров SObjectizer Environment. Каждый из них будет работать независимо от других.
  • 49. SObjectizer Team, февраль 2015 SObjectizer Environment создается функцией so_5::launch().
  • 50. SObjectizer Team, февраль 2015 SObjectizer Environment создается функцией so_5::launch(). Внутри Environment so_5::launch() запускает экземпляр SObjectizer Run-Time и возвращает управление после его останова.
  • 51. SObjectizer Team, февраль 2015 SObjectizer Environment создается функцией so_5::launch(). Внутри Environment so_5::launch() запускает экземпляр SObjectizer Run-Time и возвращает управление после его останова. Что именно будет происходить внутри запущенного Run-Time определяется пользовательской стартовой функцией.
  • 52. SObjectizer Team, февраль 2015 SObjectizer Environment создается функцией so_5::launch(). Внутри Environment so_5::launch() запускает экземпляр SObjectizer Run-Time и возвращает управление после его останова. Что именно будет происходить внутри запущенного Run-Time определяется пользовательской стартовой функцией. В случае ошибок so_5::launch() выбрасывает исключения.
  • 53. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } }
  • 54. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } } Главный заголовочный файл со всеми нужными определениями.
  • 55. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } } Стартовая функция, которая отвечает за запуск прикладной логики приложения.
  • 56. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } } Созданный экземпляр Environment, внутри которого будет работать стартовая функция и все, что в этой функции будет порождено.
  • 57. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } } Порождение Environment, запуск Run-Time и вызов стартовой функции init. Возврат из launch() произойдет когда завершат работу созданные внутри init() прикладные агенты.
  • 58. SObjectizer Team, февраль 2015 Выглядит это так: #include <iostream> #include <so_5/all.hpp> void init( so_5::rt::environment_t & env ) { ... } int main() { try { so_5::launch( &init ); } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } } Обработка ошибок, информирование о которых выполняется посредством исключений.
  • 59. SObjectizer Team, февраль 2015 Внутри стартовой функции обычно создается одна или несколько коопераций с прикладными агентами.
  • 60. SObjectizer Team, февраль 2015 Внутри стартовой функции обычно создается одна или несколько коопераций с прикладными агентами. Кооперация - это группа агентов, которые должны работать вместе и которые не могут существовать друг без друга.
  • 61. SObjectizer Team, февраль 2015 Внутри стартовой функции обычно создается одна или несколько коопераций с прикладными агентами. Кооперация - это группа агентов, которые должны работать вместе и которые не могут существовать друг без друга. Например, агенты pinger и ponger, которые обмениваются друг с другом сообщениями ping и pong.
  • 62. SObjectizer Team, февраль 2015 Внутри стартовой функции обычно создается одна или несколько коопераций с прикладными агентами. Кооперация - это группа агентов, которые должны работать вместе и которые не могут существовать друг без друга. Например, агенты pinger и ponger, которые обмениваются друг с другом сообщениями ping и pong. Нет смысла отдельно в pinger-е и отдельно в ponger-е. Эти два агента должны появляться и исчезать одновременно.
  • 63. SObjectizer Team, февраль 2015 Внутри стартовой функции обычно создается одна или несколько коопераций с прикладными агентами. Кооперация - это группа агентов, которые должны работать вместе и которые не могут существовать друг без друга. Например, агенты pinger и ponger, которые обмениваются друг с другом сообщениями ping и pong. Нет смысла отдельно в pinger-е и отдельно в ponger-е. Эти два агента должны появляться и исчезать одновременно. Именно для этого и нужны кооперации!
  • 64. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); }
  • 65. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); } Создание кооперации происходит в три этапа. Сначала Environment создает экземпляр кооперации...
  • 66. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); } Затем кооперация наполняется агентами...
  • 67. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); } Затем кооперация регистрируется.
  • 68. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); } У каждой кооперации должно быть уникальное имя, корректность которого проверяется внутри register_coop(). Но можно попросить SObjectizer самостоятельно выбрать имя для новой кооперации.
  • 69. SObjectizer Team, февраль 2015 Создание кооперации с двумя агентами: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); env.register_coop( std::move( coop ) ); } Создав кооперацию, стартовая функция завершает свою работу. Но Environment продолжит работать до тех пор, пока эта кооперация не будет дерегистрирована. Либо пока не поступит команда на останов работы Environment-а.
  • 70. SObjectizer Team, февраль 2015 Что из себя представляет агент?
  • 71. SObjectizer Team, февраль 2015 Что из себя представляет агент? Начнем с самого простого агента в этом примере. С агента ponger.
  • 72. SObjectizer Team, февраль 2015 Что из себя представляет агент? Начнем с самого простого агента в этом примере. С агента ponger. Его задача очень проста: ● получать сообщения ping; ● отвечать сообщениями pong.
  • 73. SObjectizer Team, февраль 2015 Что из себя представляет агент? Начнем с самого простого агента в этом примере. С агента ponger. Его задача очень проста: ● получать сообщения ping; ● отвечать сообщениями pong. Но сперва определим сообщения ping и pong...
  • 74. SObjectizer Team, февраль 2015 Определение сообщений: struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} };
  • 75. SObjectizer Team, февраль 2015 Определение сообщений: struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} }; Каждое сообщение должно быть представлено своим собственным C++ классом (структурой). На основании информации о типе сообщения затем происходит диспетчеризация сообщений и выбор обработчиков сообщений.
  • 76. SObjectizer Team, февраль 2015 Определение сообщений: struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} }; Все сообщения, которые переносят какие-либо данные внутри себя, должны быть унаследованы от общего базового типа so_5::rt::message_t. Бывают еще и сообщения, которые информацию внутри не переносят. Это сигналы. Подробнее они рассматриваются ниже.
  • 77. SObjectizer Team, февраль 2015 Определение сообщений: struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} }; SObjectizer не налагает каких-либо серьезных ограничений на то, что находится внутри сообщений. В данном случае поля m_req и m_resp нужны только для работы демонстрационного примера. К особенностям SObjectizer они отношения не имеют.
  • 78. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } };
  • 79. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Каждый обычный агент должен иметь свой собственный C++ класс. Могут быть еще и необычные, т.н. ad-hoc-агенты. О них речь пойдет чуть позже.
  • 80. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Класс каждого обычного агента должен наследоваться от общего базового типа, so_5::rt::agent_t.
  • 81. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Каждый агент должен быть связан с тем Environment-ом, в котором агенту предстоит работать. Поэтому ссылка на Environment должна передаваться в конструктор агента. А оттуда - в конструктор базового типа, so_5::rt::agent_t.
  • 82. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Перед тем, как агент будет зарегистрирован в составе кооперации, SObjectizer вызовет у него метод so_define_agent(). В этом методе агент должен выполнить все необходимые настройки. В частности, подписаться на интересующие его сообщения.
  • 83. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Агент ponger подписывается только на одно сообщение. Это сообщение типа ping, которое приходит из почтового ящика с именем “table”. Почтовый ящик при подписке должен указываться явно. А вот тип сообщения SObjectizer определяет сам по сигнатуре обработчика сообщения.
  • 84. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Метод, в котором агент обрабатывает сообщение, называется методом-обработчиком события. Или просто событием.
  • 85. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Породившее событие сообщение передается в метод-обработчик по константной ссылке. Метод-обработчик не должен модифицировать переданный ему экземпляр сообщения, т.к. этот же экземпляр в данный момент могут обрабатывать и другие агенты.
  • 86. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; На сообщение ping агент отвечает отсылкой сообщения pong в почтовый ящик с именем “table”.
  • 87. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Функция so_5::send конструирует объект типа pong и отсылает его в указанный почтовый ящик.
  • 88. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Дополнительные аргументы so_5::send(), которые следуют за ссылкой на почтовый ящик, передаются в конструктор объекта сообщения. В данном случае это аргумент resp для конструктора pong.
  • 89. SObjectizer Team, февраль 2015 Агент ponger: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &ponger::evt_ping ); } private : const so_5::rt::mbox_t m_table; void evt_ping( const ping & evt ) { so_5::send< pong >( m_table, evt.m_req ); } }; Агент ponger самостоятельно получает ссылку на почтовый ящик, который нужен для обмена сообщениями. В данном случае это ящик с именем “table”, который создается посредством вызова create_local_mbox(). Ссылка на почтовый ящик сохраняется внутри агента.
  • 90. SObjectizer Team, февраль 2015 Агент pinger (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); } virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); }
  • 91. SObjectizer Team, февраль 2015 Агент pinger (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); } virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); } Агент pinger очень похож на агента ponger-а: получает ссылку на Environment в конструкторе, создает ссылку на почтовый ящик с именем “table” и подписывается всего на одно сообщение в so_define_agent().
  • 92. SObjectizer Team, февраль 2015 Агент pinger (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state().event( m_table, &pinger::evt_pong ); } virtual void so_evt_start() override { so_5::send< ping >( m_table, 500 ); } Но есть одно важное отличие: метод so_evt_start(). Этот метод вызывается у агента сразу же после того, как агент и его кооперация будут успешно зарегистрированы. В этом методе агент может выполнить свои начальные действия. В данном случае - отослать первое сообщение ping.
  • 93. SObjectizer Team, февраль 2015 Агент pinger (окончание): private : const so_5::rt::mbox_t m_table; void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); } };
  • 94. SObjectizer Team, февраль 2015 Агент pinger (окончание): private : const so_5::rt::mbox_t m_table; void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); } }; В своем событии evt_pong агент pinger либо продолжает обмен сообщениями, отсылая следующий ping. Либо, если все ping-и уже были отосланы, инициирует дерегистрацию кооперации, которой он принадлежит.
  • 95. SObjectizer Team, февраль 2015 Агент pinger (окончание): private : const so_5::rt::mbox_t m_table; void evt_pong( const pong & evt ) { if( evt.m_resp ) so_5::send< ping >( m_table, evt.m_resp - 1 ); else so_deregister_agent_coop_normally(); } }; Кооперация может быть дерегистрирована по разным причинам. В данном случае указывается, что дерегистрация выполняется нормально, как это и предполагалось прикладной логикой. После дерегистрации кооперации с pinger-ом и ponger-ом, других работающих коопераций не останется. Environment завершит свою работу и произойдет возврат из so_5::launch().
  • 96. SObjectizer Team, февраль 2015 Несколько слов о почтовых ящиках (mbox-ах)...
  • 97. SObjectizer Team, февраль 2015 Несколько слов о почтовых ящиках (mbox-ах)... В SObjectizer, в отличии от похожих инструментов, вроде Erlang, Akka или CAF, сообщение отсылается не конкретному агенту (актору), а в почтовый ящик (mbox).
  • 98. SObjectizer Team, февраль 2015 Несколько слов о почтовых ящиках (mbox-ах)... В SObjectizer, в отличии от похожих инструментов, вроде Erlang, Akka или CAF, сообщение отсылается не конкретному агенту(актору), а в почтовый ящик (mbox). За mbox-ом в SObjectizer-е может скрываться как один агент, так и несколько агентов. А может и ни одного.
  • 99. SObjectizer Team, февраль 2015 В SObjectizer есть два типа mbox-ов:
  • 100. SObjectizer Team, февраль 2015 В SObjectizer есть два типа mbox-ов: Multi-Producers/Multi-Consumers mbox-ы. Похожи на “доски объявлений”. Отосланное в mbox сообщение становится доступным для всех, кто подписан на этот mbox. В примере выше продемонстрирован MPMC-mbox.
  • 101. SObjectizer Team, февраль 2015 В SObjectizer есть два типа mbox-ов: Multi-Producers/Multi-Consumers mbox-ы. Похожи на “доски объявлений”. Отосланное в mbox сообщение становится доступным для всех, кто подписан на этот mbox. В примере выше продемонстрирован MPMC-mbox. Multi-Producers/Single-Consumer mbox-ы. У этих mbox-ов только один подписчик - агент, которому принадлежит MPSC-mbox.
  • 102. SObjectizer Team, февраль 2015 Чтобы продемонстрировать особенности MPMC-mbox-ов добавим в приведенный пример еще одного агента...
  • 103. SObjectizer Team, февраль 2015 Чтобы продемонстрировать особенности MPMC- mbox-ов добавим в приведенный пример еще одного агента... Этот агент будет “слушать” обмен сообщениями между агентами pinger и ponger, подсчитывая количество пересланных сообщений.
  • 104. SObjectizer Team, февраль 2015 Агент listener: class listener : public so_5::rt::agent_t { public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); } virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; } private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0; };
  • 105. SObjectizer Team, февраль 2015 Агент listener: class listener : public so_5::rt::agent_t { public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); } virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; } private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0; }; Агенту нужно получать два сообщения. Поэтому он подписывает два своих события. Вместо методов обработчиков используются лямбда-функции. Тип сообщений, на которые производится подписка, выводится автоматически по сигнатуре лямбда-функций.
  • 106. SObjectizer Team, февраль 2015 Агент listener: class listener : public so_5::rt::agent_t { public : listener( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) , m_table( env.create_local_mbox( "table" ) ) {} virtual void so_define_agent() override { so_default_state() .event( m_table, [this]( const ping & ) { ++m_pings; } ) .event( m_table, [this]( const pong & ) { ++m_pongs; } ); } virtual void so_evt_finish() override { std::cout << "result: " << m_pings << "/" << m_pongs << std::endl; } private : const so_5::rt::mbox_t m_table; unsigned int m_pings = 0; unsigned int m_pongs = 0; }; Метод so_evt_finish() является противоположностью метода so_evt_start(). Он вызывается у агента непосредственно перед тем, как агент завершит свою работу. В данном случае этот метод используется для выдачи результатов.
  • 107. SObjectizer Team, февраль 2015 Если теперь добавить listener-а в кооперацию:
  • 108. SObjectizer Team, февраль 2015 Если теперь добавить listener-а в кооперацию: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) ); env.register_coop( std::move( coop ) ); }
  • 109. SObjectizer Team, февраль 2015 Если теперь добавить listener-а в кооперацию: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) ); env.register_coop( std::move( coop ) ); } То в конце своей работы пример напечатает: result: 501/501
  • 110. SObjectizer Team, февраль 2015 Если теперь добавить listener-а в кооперацию: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); coop->add_agent( new pinger( env ) ); coop->add_agent( new ponger( env ) ); coop->add_agent( new listener( env ) ); env.register_coop( std::move( coop ) ); } То в конце своей работы пример напечатает: result: 501/501 Т.е. отсылка сообщения в MPMC-mbox - это широковещательная рассылка всем подписчикам.
  • 111. SObjectizer Team, февраль 2015 В отличии от MPMC-mbox-а, который нужно создавать вручную, MPSC-mbox-ы создаются автоматически для каждого агента. Т.е. у каждого агента есть свой собственный MPSC-mbox, который называется direct_mbox-ом.
  • 112. SObjectizer Team, февраль 2015 В отличии от MPMC-mbox-а, который нужно создавать вручную, MPSC-mbox-ы создаются автоматически для каждого агента. Т.е. у каждого агента есть свой собственный MPSC-mbox, который называется direct_mbox-ом. Отправленное в MPSC-mbox сообщение либо отдается владельцу mbox-а на обработку, либо выбрасывается, если владелец на сообщение не подписан.
  • 113. SObjectizer Team, февраль 2015 В отличии от MPMC-mbox-а, который нужно создавать вручную, MPSC-mbox-ы создаются автоматически для каждого агента. Т.е. у каждого агента есть свой собственный MPSC-mbox, который называется direct_mbox-ом. Отправленное в MPSC-mbox сообщение либо отдается владельцу mbox-а на обработку, либо выбрасывается, если владелец на сообщение не подписан. Т.е. если два агента общаются друг с другом через direct_mbox-ы, то никто не может “прослушать” их общение.
  • 114. SObjectizer Team, февраль 2015 Однако, смысл существования direct_mbox-ов вовсе не в том, чтобы позволить двум агентам установить “закрытый канал” общения.
  • 115. SObjectizer Team, февраль 2015 Однако, смысл существования direct_mbox-ов вовсе не в том, чтобы позволить двум агентам установить “закрытый канал” общения. Direct_mbox-ы заметно эффективнее MPMC- mbox-ов, т.к. диспетчеризация сообщений для direct_mbox-ов гораздо проще и требует меньше внутренних блокировок.
  • 116. SObjectizer Team, февраль 2015 Однако, смысл существования direct_mbox-ов вовсе не в том, чтобы позволить двум агентам установить “закрытый канал” общения. Direct_mbox-ы заметно эффективнее MPMC-mbox- ов, т.к. диспетчеризация сообщений для direct_mbox-ов гораздо проще и требует меньше внутренних блокировок. Поэтому, если прикладной логике не требуется широковещательный обмен сообщениями, то лучше работать посредством direct_mbox-ов.
  • 117. SObjectizer Team, февраль 2015 В обсуждавшемся выше примере с двумя агентами pinger и ponger широковещательная рассылка не нужна.
  • 118. SObjectizer Team, февраль 2015 В обсуждавшемся выше примере с двумя агентами pinger и ponger широковещательная рассылка не нужна. Поэтому переделаем этот пример под работу с direct_mbox-ами.
  • 119. SObjectizer Team, февраль 2015 В обсуждавшемся выше примере с двумя агентами pinger и ponger широковещательная рассылка не нужна. Поэтому переделаем этот пример под работу с direct_mbox-ами. Заодно и выбросив агента listener-а. Пусть pinger и ponger сами ведут подсчет
  • 120. SObjectizer Team, февраль 2015 В обсуждавшемся выше примере с двумя агентами pinger и ponger широковещательная рассылка не нужна. Поэтому переделаем этот пример под работу с direct_mbox-ами. Заодно и выбросив агента listener-а. Пусть pinger и ponger сами ведут подсчет Ну и поменяв сообщения на сигналы
  • 121. SObjectizer Team, февраль 2015 Сигналы - это разновидность сообщений, в которых есть лишь факт существования сообщения. Но нет никаких данных внутри сообщения.
  • 122. SObjectizer Team, февраль 2015 Сигналы - это разновидность сообщений, в которых есть лишь факт существования сообщения. Но нет никаких данных внутри сообщения. Это очень напоминает пересылку атомов в Erlang, когда отсылается только атом, без какой-либо дополнительной информации.
  • 123. SObjectizer Team, февраль 2015 При использовании SObjectizer сигналы оказались настолько распространены, что для их поддержки добавлены специальные механизмы.
  • 124. SObjectizer Team, февраль 2015 При использовании SObjectizer сигналы оказались настолько распространены, что для их поддержки добавлены специальные механизмы. На уровне API работа с сигналами в чем-то похожа на работу с сообщениями. В чем-то нет.
  • 125. SObjectizer Team, февраль 2015 Меняем сообщения ping и pong на сигналы...
  • 126. SObjectizer Team, февраль 2015 Меняем сообщения ping и pong на сигналы... struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} }; struct ping : public so_5::rt::signal_t {}; struct pong : public so_5::rt::signal_t {};
  • 127. SObjectizer Team, февраль 2015 Меняем сообщения ping и pong на сигналы... Сигналы должны наследоваться от so_5::rt::signal_t и не должны содержать данных. struct ping : public so_5::rt::message_t { unsigned int m_req; ping( unsigned int req ) : m_req{ req } {} }; struct pong : public so_5::rt::message_t { unsigned int m_resp; pong( unsigned int resp ) : m_resp{ resp } {} }; struct ping : public so_5::rt::signal_t {}; struct pong : public so_5::rt::signal_t {};
  • 128. SObjectizer Team, февраль 2015 Меняем агента pinger-а...
  • 129. SObjectizer Team, февраль 2015 Меняем агента pinger-а (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; } virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); }
  • 130. SObjectizer Team, февраль 2015 Меняем агента pinger-а (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; } virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); } direct_mbox становится доступен только после создания агента. Поэтому для связывания pinger-а и ponger-а потребовался отдельный метод, который будет вызываться после создания обоих агентов.
  • 131. SObjectizer Team, февраль 2015 Меняем агента pinger-а (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; } virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); } В метод event() передается всего один аргумент: лямбда-функция с обработчиком сигнала. В этом случае event() делает подписку на сигнал, поступающий от direct_mbox-а агента.
  • 132. SObjectizer Team, февраль 2015 Меняем агента pinger-а (начало): class pinger : public so_5::rt::agent_t { public : pinger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_ponger_mbox( const so_5::rt::mbox_t & mbox ) { m_ponger = mbox; } virtual void so_define_agent() override { so_default_state().event< pong >( [this]{ ++m_pongs; so_5::send< ping >( m_ponger ); } ); } При подписке на сигнал нужно явно указывать тип сигнала. Обработчиком сигнала должен быть метод или лямбда-функция без параметров. В отличии от сообщения, нет экземпляра сигнала, поэтому нечего передавать параметром обработчику события.
  • 133. SObjectizer Team, февраль 2015 Меняем агента pinger-а (окончание): virtual void so_evt_start() override { so_5::send< ping >( m_ponger ); } virtual void so_evt_finish() override { std::cout << "pongs: " << m_pongs << std::endl; } private : so_5::rt::mbox_t m_ponger; unsigned int m_pongs = 0; };
  • 134. SObjectizer Team, февраль 2015 Меняем агента pinger-а (окончание): virtual void so_evt_start() override { so_5::send< ping >( m_ponger ); } virtual void so_evt_finish() override { std::cout << "pongs: " << m_pongs << std::endl; } private : so_5::rt::mbox_t m_ponger; unsigned int m_pongs = 0; }; Отсылка сигнала выполняется той же функцией so_5::send(), что и отсылка сообщения. Но после mbox-а получателя больше никаких аргументов не требуется.
  • 135. SObjectizer Team, февраль 2015 class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; } virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); } Аналогичным образом меняется агент ponger (начало):
  • 136. SObjectizer Team, февраль 2015 virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; } private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0; }; Аналогичным образом меняется агент ponger (окончание):
  • 137. SObjectizer Team, февраль 2015 void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); env.register_coop( std::move( coop ) ); } Создание кооперации становится более многословным:
  • 138. SObjectizer Team, февраль 2015 void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); env.register_coop( std::move( coop ) ); } Создание кооперации становится более многословным: Кроме того, здесь есть ошибка...
  • 139. SObjectizer Team, февраль 2015 void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); env.register_coop( std::move( coop ) ); } Создание кооперации становится более многословным: Кроме того, здесь есть ошибка... Никто не остановит этих агентов! Они будут пинговать друг друга постоянно.
  • 140. SObjectizer Team, февраль 2015 Исправим проблему, добавив еще одного агента, который завершит работу примера через одну секунду...
  • 141. SObjectizer Team, февраль 2015 Исправим проблему, добавив еще одного агента, который завершит работу примера через одну секунду... Поскольку агент будет обрабатывать всего одно событие, нет смысла определять отдельный класс для этого агента, переопределять в нем метод so_define_agent() и т.д.
  • 142. SObjectizer Team, февраль 2015 Исправим проблему, добавив еще одного агента, который завершит работу примера через одну секунду... Поскольку агент будет обрабатывать всего одно событие, нет смысла определять отдельный класс для этого агента, переопределять в нем метод so_define_agent() и т.д. Вместо этого создадим ad-hoc-агента. Т.е. агента, описанного “по месту”, без дополнительных формальностей.
  • 143. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы:
  • 144. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } );
  • 145. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); Сигнал на завершение работы.
  • 146. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); Создание ad-hoc-агента. Возвращается дескриптор, через который агента можно настраивать.
  • 147. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); Новый агент подписывается на единственный сигнал stop.
  • 148. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); Сигнал придет на direct_mbox нового агента.
  • 149. SObjectizer Team, февраль 2015 Ad-hoc-агент для завершения примера через секунду после начала работы: struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); Обработчик этого сигнала даст приказ SObjectizer Environment завершить работу примера. Единственная кооперация будет дерегистрирована автоматически.
  • 150. SObjectizer Team, февраль 2015 Ad-hoc-агент создан и настроен. Осталось отослать отложенный на одну секунду сигнал stop:
  • 151. SObjectizer Team, февраль 2015 Ad-hoc-агент создан и настроен. Осталось отослать отложенный на одну секунду сигнал stop: env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) );
  • 152. SObjectizer Team, февраль 2015 Ad-hoc-агент создан и настроен. Осталось отослать отложенный на одну секунду сигнал stop: env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); Функция so_5::send_delayed отсылает отложенное на указанное время сообщение или сигнал. В данном случае сигнал stop на direct_mbox нового ad-hoc-агента через одну секунду.
  • 153. SObjectizer Team, февраль 2015 В итоге стартовая функция приняла вид: void init( so_5::rt::environment_t & env ) { auto coop = env.create_coop( so_5::autoname ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent(); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); }
  • 154. SObjectizer Team, февраль 2015 Запускаем обновленный пример...
  • 155. SObjectizer Team, февраль 2015 Запускаем обновленный пример... Получаем... pongs: 4441168 pings: 4441169
  • 156. SObjectizer Team, февраль 2015 Запускаем обновленный пример... Получаем... pongs: 4441168 pings: 4441169 Итого больше 8M сообщений в секунду.
  • 157. SObjectizer Team, февраль 2015 Итого больше 8M сообщений в секунду Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit, Visual C++ 2013 64-bit Запускаем обновленный пример... Получаем... pongs: 4441168 pings: 4441169
  • 158. SObjectizer Team, февраль 2015 Итого больше 8M сообщений в секунду Core i7 2.4GHz, 8GiB RAM, Win8.1 64-bit, Visual C++ 2013 64-bit Запускаем обновленный пример... Получаем... pongs: 4441168 pings: 4441169 Это хорошо, но на каком контексте работают агенты в данном примере?
  • 159. SObjectizer Team, февраль 2015 Все агенты работают на одной общей рабочей нити!
  • 160. SObjectizer Team, февраль 2015 Все агенты работают на одной общей рабочей нити! Т.е. никакой многопоточности пока не видно. Пример показал лишь возможности по передаче сообщений между агентами, разделяющими общий рабочий контекст.
  • 161. SObjectizer Team, февраль 2015 Все агенты работают на одной общей рабочей нити! Т.е. никакой многопоточности пока не видно. Пример показал лишь возможности по передачи сообщений между агентами, разделяющими общий рабочий контекст. Но кто выбирает рабочий контекст для агентов? И как привязать агента к другому контексту?
  • 162. SObjectizer Team, февраль 2015 Все агенты работают на одной общей рабочей нити! Т.е. никакой многопоточности пока не видно. Пример показал лишь возможности по передачи сообщений между агентами, разделяющими общий рабочий контекст. Но кто выбирает рабочий контекст для агентов? И как привязать агента к другому контексту? Контекст выбирает программист, указывая, на каком диспетчере должен работать агент. Если диспетчер не указан, то агент привязывается к диспетчеру по умолчанию.
  • 163. SObjectizer Team, февраль 2015 Все агенты работают на одной общей рабочей нити! Т.е. никакой многопоточности пока не видно. Пример показал лишь возможности по передачи сообщений между агентами, разделяющими общий рабочий контекст. Но кто выбирает рабочий контекст для агентов? И как привязать агента к другому контексту? Контекст выбирает программист, указывая, на каком диспетчере должен работать агент. Если диспетчер не указан, то агент привязывается к диспетчеру по умолчанию. Как это и произошло в данном примере.
  • 164. SObjectizer Team, февраль 2015 Диспетчер по умолчанию запускает события всех своих агентов на одной общей рабочей нити. Для этих агентов получается что-то вроде кооперативной многозадачности. Если кто-то стал “тормозить”, то “тормозить” начинают и остальные.
  • 165. SObjectizer Team, февраль 2015 Диспетчер по умолчанию запускает события всех своих агентов на одной общей рабочей нити. Для этих агентов получается что-то вроде кооперативной многозадачности. Если кто-то стал “тормозить”, то “тормозить” начинают и остальные. Но можно создать произвольное количество необходимых приложению диспетчеров и привязать своих агентов к этим диспетчерам.
  • 166. SObjectizer Team, февраль 2015 Заставим агентов pinger и ponger работать на разных рабочих нитях (чтобы у каждого из них была своя собственная рабочая нить)...
  • 167. SObjectizer Team, февраль 2015 Заставим агентов pinger и ponger работать на разных рабочих нитях (чтобы у каждого из них была своя собственная рабочая нить)... Для этого создадим диспетчера active_obj и привяжем агентов к нему.
  • 168. SObjectizer Team, февраль 2015 Заставим агентов pinger и ponger работать на разных рабочих нитях (чтобы у каждого из них была своя собственная рабочая нить)... Для этого создадим диспетчера active_obj и привяжем агентов к нему. Данный диспетчер каждому своему агенту выделяет отдельную рабочую нить (агент оказывается активным объектом).
  • 169. SObjectizer Team, февраль 2015 Для этого ничего не нужно менять в агентах...
  • 170. SObjectizer Team, февраль 2015 Для этого ничего не нужно менять в агентах... Изменения затронут только стартовую функцию.
  • 171. SObjectizer Team, февраль 2015 Привязка агентов к разным диспетчерам: void init( so_5::rt::environment_t & env ) { env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp ); auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); }
  • 172. SObjectizer Team, февраль 2015 Привязка агентов к разным диспетчерам: void init( so_5::rt::environment_t & env ) { env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp ); auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); } Просьба создать диспетчера с активными объектами под именем “active_obj”. Если такого диспетчера еще нет, то он будет создан с помощью указанной фабрики.
  • 173. SObjectizer Team, февраль 2015 Привязка агентов к разным диспетчерам: void init( so_5::rt::environment_t & env ) { env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp ); auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); } Указание кооперации о том, что основным диспетчером для ее агентов будет диспетчер с именем “active_obj”.
  • 174. SObjectizer Team, февраль 2015 Привязка агентов к разным диспетчерам: void init( so_5::rt::environment_t & env ) { env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp ); auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); } Агенты pinger и ponger добавляются в кооперацию без каких- либо дополнительных инструкций. Значит они будут привязаны к тому диспетчеру, который для кооперации считается основным диспетчером. В данном случае это будет диспетчер с именем “active_obj”.
  • 175. SObjectizer Team, февраль 2015 Привязка агентов к разным диспетчерам: void init( so_5::rt::environment_t & env ) { env.add_dispatcher_if_not_exists( "active_obj", &so_5::disp::active_obj::create_disp ); auto coop = env.create_coop( so_5::autoname, so_5::disp::active_obj::create_disp_binder("active_obj") ); auto a_pinger = coop->add_agent( new pinger( env ) ); auto a_ponger = coop->add_agent( new ponger( env ) ); a_pinger->set_ponger_mbox( a_ponger->so_direct_mbox() ); a_ponger->set_pinger_mbox( a_pinger->so_direct_mbox() ); struct stop : public so_5::rt::signal_t {}; auto stopper = coop->define_agent( so_5::rt::create_default_disp_binder() ); stopper.event< stop >( stopper.direct_mbox(), [&env]{ env.stop(); } ); env.register_coop( std::move( coop ) ); so_5::send_delayed< stop >( env, stopper.direct_mbox(), std::chrono::seconds(1) ); } А вот для агента stopper-а отдельная рабочая нить не нужна. Поэтому этот объект явным образом привязывается к диспетчеру SObjectizer по умолчанию. Если такого прямого указания не сделать, то для агента будет выполнена привязка к основному диспетчеру кооперации.
  • 176. SObjectizer Team, февраль 2015 Что получается после запуска обновленного примера?
  • 177. SObjectizer Team, февраль 2015 Что получается после запуска обновленного примера? pings: pongs: 1234623 1234624
  • 178. SObjectizer Team, февраль 2015 Что получается после запуска обновленного примера? pings: pongs: 1234623 1234624 Упс… Или так и должно быть?
  • 179. SObjectizer Team, февраль 2015 Что получается после запуска обновленного примера? pings: pongs: 1234623 1234624 Упс… Или так и должно быть? Это, действительно упс. Но так и должно быть
  • 180. SObjectizer Team, февраль 2015 Что получается после запуска обновленного примера? pings: pongs: 1234623 1234624 Упс… Или так и должно быть? Это, действительно упс. Но так и должно быть Могло бы быть и еще страшнее
  • 181. SObjectizer Team, февраль 2015 Что же произошло? pings: pongs: 1234623 1234624
  • 182. SObjectizer Team, февраль 2015 Что же произошло? pings: pongs: 1234623 1234624 Агенты pinger и ponger стали работать на разных нитях и конкурировать за доступ к std:: cout. В результате этой конкуренции вывод в std::cout перемешался. Мог бы перемешаться еще больше. А мог бы и не перемешаться вовсе. Многопоточность…
  • 183. SObjectizer Team, февраль 2015 Что еще произошло? pings: pongs: 1234623 1234624
  • 184. SObjectizer Team, февраль 2015 Что еще произошло? pings: pongs: 1234623 1234624 Упала общая производительность примера. Если на одной нити был показан результат в 8M сообщений в секунду, то на двух нитях - всего 2M сообщений.
  • 185. SObjectizer Team, февраль 2015 Что еще произошло? pings: pongs: 1234623 1234624 Упала общая производительность примера. Если на одной нити был показан результат в 8M сообщений в секунду, то на двух нитях - всего 2M сообщений. Что вполне ожидаемо, т.к. передача единичных сообщений с одной нити на другую - это дорогостоящая операция.
  • 186. SObjectizer Team, февраль 2015 Но что изменилось в самих агентах?
  • 187. SObjectizer Team, февраль 2015 Но что изменилось в самих агентах? Ничего.
  • 188. SObjectizer Team, февраль 2015 Агент ponger для одной рабочей нити: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; } virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); } virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; } private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0; };
  • 189. SObjectizer Team, февраль 2015 Агент ponger для одной рабочей нити: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; } virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); } virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; } private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0; }; Агент ponger для двух рабочих нитей: class ponger : public so_5::rt::agent_t { public : ponger( so_5::rt::environment_t & env ) : so_5::rt::agent_t( env ) {} void set_pinger_mbox( const so_5::rt::mbox_t & mbox ) { m_pinger = mbox; } virtual void so_define_agent() override { so_default_state().event< ping >( [this]{ ++m_pings; so_5::send< pong >( m_pinger ); } ); } virtual void so_evt_finish() override { std::cout << "pings: " << m_pings << std::endl; } private : so_5::rt::mbox_t m_pinger; unsigned int m_pings = 0; };
  • 190. SObjectizer Team, февраль 2015 Это прямое следствие того, что агенты взаимодействовали друг с другом только посредством асинхронных сообщений.
  • 191. SObjectizer Team, февраль 2015 Это прямое следствие того, что агенты взаимодействовали друг с другом только посредством асинхронных сообщений. Поэтому им все равно, на каком контексте они работают.
  • 192. SObjectizer Team, февраль 2015 Это прямое следствие того, что агенты взаимодействовали друг с другом только посредством асинхронных сообщений. Поэтому им все равно, на каком контексте они работают. А задачей SObjectizer-а является предоставление программисту возможности выбрать нужный ему контекст путем привязки агентов к соответствующим диспетчерам.
  • 193. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”:
  • 194. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”: ● one_thread. Запускает всех агентов на одной общей рабочей нити;
  • 195. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”: ● one_thread. Запускает всех агентов на одной общей рабочей нити; ● active_obj. Предоставляет каждому агенту отдельную нить в единоличное пользование;
  • 196. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”: ● one_thread. Запускает всех агентов на одной общей рабочей нити; ● active_obj. Предоставляет каждому агенту отдельную нить в единоличное пользование; ● active_group. Предоставляет отдельную нить в единоличное пользование группе объектов;
  • 197. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”: ● one_thread. Запускает всех агентов на одной общей рабочей нити; ● active_obj. Предоставляет каждому агенту отдельную нить в единоличное пользование; ● active_group. Предоставляет отдельную нить в единоличное пользование группе объектов; ● thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты могут мигрировать с одной рабочей нити на другую. Но агент не может работать на двух рабочих нитях одновременно;
  • 198. SObjectizer Team, февраль 2015 Для этого в SObjectizer есть целый ряд готовых диспетчеров “из коробки”: ● one_thread. Запускает всех агентов на одной общей рабочей нити; ● active_obj. Предоставляет каждому агенту отдельную нить в единоличное пользование; ● active_group. Предоставляет отдельную нить в единоличное пользование группе объектов; ● thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты могут мигрировать с одной рабочей нити на другую. Но агент не может работать на двух рабочих нитях одновременно; ● adv_thread_pool. Выделяет агентам нити из пула рабочих нитей. Агенты могут и мигрировать с одной рабочей нити на другую, и работать сразу на нескольких (при условии, что их обработчики событий объявлены thread safe).
  • 199. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера...
  • 200. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров.
  • 201. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров. Например:
  • 202. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров. Например: ● один one_thread диспетчер для агента-клиента AMQP;
  • 203. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров. Например: ● один one_thread диспетчер для агента-клиента AMQP; ● один thread_pool диспетчер для обработки прочитанных из AMQP- очередей запросов;
  • 204. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров. Например: ● один one_thread диспетчер для агента-клиента AMQP; ● один thread_pool диспетчер для обработки прочитанных из AMQP- очередей запросов; ● один active_obj диспетчер для агентов, выполняющих работу с СУБД;
  • 205. SObjectizer Team, февраль 2015 При этом разработчик может не только выбирать нужный ему тип диспетчера... ...Но и создавать в своем приложении нужное ему количество нужных ему типов диспетчеров. Например: ● один one_thread диспетчер для агента-клиента AMQP; ● один thread_pool диспетчер для обработки прочитанных из AMQP- очередей запросов; ● один active_obj диспетчер для агентов, выполняющих работу с СУБД; ● еще один active_obj диспетчер для агентов, работающих с подключенными к компьютеру HSM-ами;