пятница, 7 апреля 2017 г.

[prog.c++] Тема movable/modifiable сообщений в SObjectizer задышала

В конце февраля, после C++ Russia 2017, возникла тема добавления в SObjectizer поддержки не константных экземпляров сообщений. Суть в том, что в SObjectizer из-за первоначальной направленности на взаимодействие в режиме 1:N, все сообщения доставлялись получателям в виде константных объектов. Получатель имел константную ссылку на пришедшее к нему сообщение и не должен был менять этот объект, т.к. в это же время то же самое сообщение мог обрабатывать еще кто-то.

Для некоторых сценариев это оказалось не очень хорошо. Например, если цепочка агентов выстраивается в конвейер, по которому движется большой объект, а каждый из агентов должен что-то в этом объекте поменять и передать измененный объект дальше. Или когда один агент должен передать "тяжелый" объект другому агенту, но использовать shared_ptr для этих целей не выгодно.

В итоге мы начали думать, как дать возможность пересылать не константные объекты-сообщения при взаимодействии агентов в режиме 1:1. Сначала идеи крутились вокруг movable-сообщений, т.е. сообщений, содержимое которых можно перемещать между экземплярами (например, когда кто-то делает send, то содержимое сообщение сразу же конструируется где-то в заранее созданном буфере у агента-получателя). Но затем была выбрана, как мне представляется, более простая идея: мы применили к сообщениям тот же подход, который в C++ используется для динамически-созданных объектов и unique_ptr. Класс unique_ptr говорит разработчику, что есть только один "владеющий" указатель на объект. Нельзя расплодить unique_ptr, можно лишь передавать право владения так, что только один unique_ptr будет владеть динамически созданным объектом.

Мы добавили в SObjectizer такое понятие, как unique_mbox. Т.е. специальный тип mbox-а, отсылка сообщения в который приводит к передаче не константного объекта-сообщения. Для того, чтобы получить не константное сообщение из unique_mbox-а, обработчик сообщения должен использовать специальный новый тип unique_mhood_t<Msg>. Это тонкая шаблонная обертка, похожая на уже существующий mhood_t, но она позволяет модифицировать полученный объект-сообщение. Так же unique_mhood_t позволяет переслать не константное сообщение дальше.

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

среда, 5 апреля 2017 г.

[prog.c++] Альфа-версия RESTinio, инструмента для реализации REST API на C++

Мы долго смотрели по сторонам на то, что есть в C++ для разработки HTTP-сервисов и REST-сервисов в частности. И решили все-таки попробовать сделать что-то свое. Попробовали. Сегодня выкатываем в мир первую альфа-версию небольшого, header-only, кросс-платформенного инструмента под названием RESTinio. Его главная задача -- упростить асинхронную обработку запросов. Чтобы, грубо говоря, обработчик спокойно мог потратить 15 секунд на формирование ответа, но это бы не влияло на параллельные запросы.

В основе лежит Asio и http_parser из NodeJS. SObjectizer для работы RESTinio не нужен. Но обработка запросов легко может делегироваться из RESTinio в SObjectizer. Пример того, как это делается можно найти в репозитории.

Все это началось с задачки, где для обработки одного запроса нужно было провзаимодействовать с несколькими внешними системами и все это могло занять от нескольких секунд до нескольких десятков секунд. Интеграция с внешними системами должна была лечь на SObjectizer, но наружу нужно было выставить RESTful API. Который нужно было на чем-то сделать. Причем сделать так, чтобы длительная обработка отдельных запросов не мешала обслуживанию запросов от большого числа пользователей.

Ну и это еще одно подтверждение того, что мы уже несколько раз говорили на конференциях в статьях: мы больше смотрим в сторону того, чтобы дать возможность агентам общаться с внешним миром посредством де-факто стандартных протоколов, вроде HTTP ;) При этом планов привязать RESTinio намертво к SObjectizer-у у нас нет. Тут все просто: из SObjectizer должно быть удобно пользоваться RESTinio, но самому RESTinio SObjectizer для работы не нужен.

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

воскресенье, 2 апреля 2017 г.

[prog.c++] Аннотированный код нового примера для SObjectizer-5.5.19

Вот уже пару месяцев идет активная работа над новой версией SObjectizer -- 5.5.19. Одна из основных фич этой версии уже вполне себе заработала. Речь про возможность запустить SObjectizer Environment в однопоточном режиме. Кратко поясню, в чем суть.

Обычный SObjectizer Environment для выполнения своей работы запускает три дополнительные рабочие нити. Первая принадлежит диспетчеру по умолчанию (к этому диспетчеру агенты привязываются, если пользователь явно не указал, на каком диспетчере агент должен работать). Вторая обслуживает таймер (она так и называется -- таймерная нить). Третья нить нужна для того, чтобы корректно завершать дерегистрацию коопераций и давать возможность диспетчерам завершать рабочие нити, созданные под обслуживание этих коопераций.

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

Как раз для поддержки подобных случаев в SO-5.5.19 добавляется возможность создать такой SObjectizer Environment, который будет все свои действия выполнять на одной-единственной нити. Т.е. диспетчер по умолчанию, таймер и окончательная дерегистрация будут работать на той самой нити, на которой был произведен вызов so_5::launch().

Фича эта уже работает, но мы пока еще не проверили ее во всех сценариях, для которых она предназначалась. Поэтому пока не можем считать ее готовой к релизу. Но в процессе ее реализации в список примеров SObjectizer-а был добавлен еще один пример. Мне кажется, он достаточно интересен и демонстрирует использование многопоточности вообще без агентов. Только голые нити и CSP-шные каналы (называющиеся у нас mchain-ы). Ну и очередная разновидность ping-pong-а, только на этот раз с использованием таймеров. Пример, снабженный комментариями, под катом. Кому интересно, милости прошу посмотреть и высказать свое фи авторитетное мнение.

Напоследок скажу, что в скоуп версии 5.5.19 входит еще одна важная фича -- это moveable-сообщения, о которых речь заходила с месяц назад. Работы здесь еще очень много. Так что пока даже не рискну предположить предполагаемую дату релиза. Хорошо бы успеть к концу апреля, но загадывать не берусь. Жаль, что работы над 5.5.19 так затянулись, но однопоточный SObjectizer Environment -- это настолько переворачивающая все с ног на голову переделка SO-5, что торопиться ну очень не хочется.

Итак, сам код:

суббота, 1 апреля 2017 г.

[life.cinema] Очередной кинообзор (2017/03)

Подошло время очередного кинообзора. На этот раз в списке всего два нормальных фильма (и это,  к сожалению, отнюдь не первоапрельская шутка). Остальное просто шлак, на который можно не тратить свое время.
Невидимый гость (Contratiempo, 2016). Европейский криминальный фильм. Снятый в своей, очень отличающейся от голливудской, стилистике. Посмотрел с большим удовольствием.
Гуляй, Вася (2017). Вот просто на удивление неплохой фильм. Понравилось. Хотя, подозреваю, фильм сильно на любителя, и не могу утверждать, что он понравится еще кому-то.
Закон ночи (Live by Night, 2016). Очень тщательно сделанный фильм. Смотришь и получаешь визуальное наслаждение от того, как фильм снят и какая там картинка. Но вот все остальное довольно уныло и неинтересно, даже никому из героев фильма сопереживать не хочется.
Новогодний корпоратив (Office Christmas Party, 2016). После трейлера ожидал, что будет такой же треш и угар, как в "Мальчишнике в Вегасе". Но получилось весьма уныло и практически не смешно.
Видели ночь (All Nighter, 2017). Посмотрел из-за участия Дж.К.Симмонса в главных ролях. Но его одного не хватило, фильм получился довольно посредственным.
Логан (Logan, 2017). По отзывам критиков перед фильмом ждал чего-то другого. Оказалось, что как был фильм по комиксам, так он и остался. Трейлер для "Логана" оказался намного интереснее и суровее самого "Логана".
Конг: Остров черепа (Kong: Skull Island, 2017). Красочно. Но накал идиотии просто зашкаливает. Потраченного на фильм времени очень жалко.
Три икса: Мировое господство (xXx: Return of Xander Cage, 2017). Либо это кино для детей младшего школьного возраста, либо я так и не понял, что это, блин, такое было.
Живое (Life, 2017). Снято красиво, но муть редкая. Постоянно задаешь себе вопрос: что за херню нам показывают?
Обитель зла: Последняя глава (Resident Evil: The Final Chapter, 2017). Посмотрел только для того, чтобы увидеть, до какого маразма дошли создатели этой серии фильмов. Лучше бы не смотрел.

пятница, 31 марта 2017 г.

[prog.thoughts] Блеск и нищета C++

C++ -- это, блин, язык контрастов. В один день доводится увидеть совершенно крышесносящие примеры сочетания техники CRTP и variadic templates и наглядную демонстрацию того, как на C++ программируют в реальном мире.

Серьезно, если кто-то еще не читал эту небольшую PDF-у, в которой показываются трюки вроде:

template <typename N, template <typename...> class... CRTPs>
class Number : public CRTPs<Number<N, CRTPs...>>... {
public:
   using S = decay_t<underlying_arithmetic_type_t<N>>;
   constexpr Number() // note: intentionally uninitialized
       {}
   constexpr Number(S value)
       : value_(value) {}
   constexpr S value() const
       { return value_; }
   constexpr void set_value(S a)
       { value_ = a; }
private:
   N value_;
};

template <typename T>
class Stream_i {
   friend std::ostream &operator <<(std::ostream &a, T b)
      { return a << b.value(); }
};

template <typename T>
class Shift_i {
   friend T operator <<(T a, T b)
      { return T(a.value() << b.value()); }
   friend T operator >>(T a, T b)
      { return T(a.value() >> b.value()); }
};

template <typename T>
class Eq_i {
   friend constexpr bool operator ==(T a, T b)
      { return a.value() == b.value(); }
   friend constexpr bool operator !=(T a, T b)
      { return a.value() != b.value(); }
};
...

using restricted_int = Number<int, Eq_i, Rel_i, Add_i, Stream_i>;
   // Supports only ==, !=, <, >, <=, >=, +, +=, <<(ostream).

то очень рекомендую. От нового взгляда на возможности современного C++ глаза распахиваются еще шире :)

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

И на этом фоне реальный топик с LOR-а, в котором человек приводит свой код и просит подсказать, в чем проблема.

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

вторник, 28 марта 2017 г.

[prog.c++] Библиотека timertt обновилась до версии 1.1.3

Вышла обновленная версия библиотеки timertt для работы с таймерами в C++ -- 1.1.3. В этой версии в публичный интерфейс timer_manager и timer_thread добавлена функция empty(), которая проверяет, пуст ли список таймеров или нет.

Признаюсь, это глупый косяк, который был допущен пару лет назад. В потрохах библиотеки empty() был реализован для всех timer_engine, но вот наружу я его тупо забыл вытащить (объект timer_engine инкапсулирован внутри timer_manager/timer_thread и просто так его методы недоступны).

Библиотека разрабатывалась для замены ACE в проекте SObjectizer, поэтому все, что связано с timertt, находится на SourceForge:

  • архивы с исходными текстами доступны в секции Files. Архив timertt-1.1.3-headeronly.7z содержит только основной заголовочный файл со всей функциональностью timertt. Архив timertt-1.1.3-full.7z содержит так же тесты, примеры и сгенерированный посредством Doxygen API Reference Manual;
  • основная документация для проекта собрана в Wiki;
  • исходники лежат в Subversion-репозитории на SourceForge. Релизные версии в tags/timertt, находящиеся в разработке версии в branches/timertt.

понедельник, 27 марта 2017 г.

[prog.flame] Rust-оманы зря пытаются продавать Rust С++никам, им бы поменять целевую аудиторию :)

Данный пост возник под впечатлением от двух недавних больших срачей на reddit-е на тему о том, почему Rust лучше C++: Have you used Rust? Do you prefer it over Modern C++? и Things I love about Rust while being a C++ programmer. А так же интересным ссылкам, которые проскочили в этих обсуждениях, например: вот (про некоторые проблемы Rust) или вот (специально для тех, кто верит, что безопасность Rust-а не имеет платы в run-time). Кроме шуток, срачи интересные, помимо обычного булшита (например, в очередной раз всплыл аргумент о том, как классно иметь возможность во время компиляции подключиться к СУБД, выкачать оттуда описание схемы данных и сгенерировать ORM) встречаются и прикольные примеры C++ граблей на ровном месте. Вот, скажем: