суббота, 2 апреля 2016 г.

[prog.c++] Похоже, наткнулся на баг в С++ компиляторе из Visual Studio 2015 Update 2

Установил себе сегодня Visual Studio 2015 Update 2, попытался скомпилировать SObjectizer. Столкнулся с тем, что перестал работать один из тестов. Тест выбрасывал исключение из функции, которая вызывается из noexcept-функции. Это должно приводить к аварийному завершению теста. Но не приводит.

Грешу на проблему в обновленном VC++, ибо предыдущий компилятор отрабатывал нормально. Грубо говоря, вот такой код:

template< typename LAMBDA, typename MESSAGE >
class lambda_as_filter_t : public delivery_filter_t
   {
      LAMBDA m_filter;

   public :
      lambda_as_filter_t( LAMBDA && filter )
         :  m_filter( std::forward< LAMBDA >( filter ) )
         {}

      virtual bool
      check(
         const agent_t & /*receiver*/,
         const message_t & msg ) const noexcept override
         {
            return m_filter(message_payload_type< MESSAGE >::payload_reference( msg ));
         }
   };

Должен приводить к краху приложения, если при вызове m_filter(msg) выскакивает исключение. Но не приводит.

Если же сделать вот такой workaround:

template< typename LAMBDA, typename MESSAGE >
class lambda_as_filter_t : public delivery_filter_t
   {
      LAMBDA m_filter;

      bool
      do_check( const MESSAGE & m ) const noexcept
      {
         return m_filter( m );
      }

   public :
      lambda_as_filter_t( LAMBDA && filter )
         :  m_filter( std::forward< LAMBDA >( filter ) )
         {}

      virtual bool
      check(
         const agent_t & /*receiver*/,
         const message_t & msg ) const noexcept override
         {
            return do_check(message_payload_type< MESSAGE >::payload_reference( msg ));
         }
   };

То все начинает работать так, как и ожидалось: приложение падает.

Подозреваю, что здесь сказывается то, что базовый класс, delivery_filter_t, из которого наследуется метод check(), экспортируется из DLL. А конкретные экземпляры lambda_as_filter_t генерируются внутри приложение, которое линкует эту DLL. Но пока минимального примера, явно указывающего наличие этой проблемы, сделать не удалось (я пробовал без DLL-ек, но баг не проявился). Может, однако, еще какие-то проблемы сказываются.

В общем, неприятная штука. Как бы не пришлось себе откатывать VS на Update1.

Upd. Засабмитил в Microsoft. Посмотрим, что ответят. И ответят ли.

четверг, 31 марта 2016 г.

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

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


День выборов 2 (2016). Нормально. Но до уровня первого фильма не дотянули, к сожалению.

Джейн берет ружье (Jane Got a Gun, 2015) и Заброшенный (Forsaken, 2015). Два вполне добротных вестерна. Оба не шедевры, но оба посмотрел с удовольствием.

Дедпул (Deadpool, 2016). Мне показалось, что самая сильная сцена -- это разборка на мосту, которая практически вся была показана в трейлере. В остальном откровенная тупизна, но скрытая под большим слоем черного и несколько пошловатого юмора.

Конец света 2013: Апокалипсис по-голливудски (This Is the End, 2013). Ребята оторвались, сняли совершенно тупую, но смешную комедию с невероятным стебом над самими собой. Особенно доставил Ченнинг Татум :)

В центре внимания (Spotlight, 2015). Тема, конечно же, в фильме поднята не простая. Но вот сам фильм почти не цепляет.

Падение Лондона (London Has Fallen, 2016). Нормальный такой боевичок: стреляют, взрывают, морды бьют. Как раз хороший вариант для просмотра с отключенными мозгами.

Кловерфилд, 10 (10 Cloverfield Lane, 2016). У меня фильм оставил такое же неоднозначное впечатление, как и предыстория, известная у нас под названием Монстро. В общем, ждал большего. А тут довольно средненький фильм на один просмотр.

Бетмен против Супермена: На заре справедливости (Batman v Superman: Dawn of Justice, 2016). Просто откровенная бредятина, даже удивительно, как решился такое посмотреть.

Боги Египта (Gods of Egypt, 2016). Редкая ерундистика. Даже спецэффекты не спасают.

[prog] Mxx_ru 1.6.9

Mxx_ru обновился до версии 1.6.9. В этой версии реализована поддержка звездочек в именах, указываемых в map/map_dir и map_file (подробнее в предыдущем посте).

Установить Mxx_ru можно командой gem install Mxx_ru

Обновить Mxx_ru можно командой gem update Mxx_ru

Так же Mxx_ru можно загрузить с SourceForge (gem-файл).

PS. Документация пока не обновлялась из-за отсутствия времени :(

среда, 30 марта 2016 г.

[prog.c++14] Хабровские примеры из батла Go vs D, но на SO-5.5.16

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

Меня лично статья удивила. Мне почему-то казалось, что на D такие игрушечные примеры должны получаться короче и проще. Но, надеюсь, автор статьи лучше понимал, что и как он делает. Мой же интерес в том, чтобы проверить возможности SO-5 на этом же поле.

Для чего на SO-5 было реализована два примера. Краткий их разбор под катом. Взять поиграться их можно из github-овского репозитория (для сборки нужны Ruby+rake+Mxx_ru, заодно там возможности MxxRu::externals можно увидеть).

вторник, 29 марта 2016 г.

[prog] По следам опыта с Mxx_ru-1.6.8 и перед релизом Mxx_ru-1.6.9

Накопился некоторый, пусть и небольшой, опыт работы с MxxRu::externals из Mxx_ru-1.6.8. Хорошая новость: externals-ы таки работают. А вот плохих новостей нет :)

Однако, уже очевидно, что некоторые доработки нужны.

Прежде всего, оказалось желательно разрешит переименования исходного каталога в команде map_dir. Например, был каталог some-prj/src/lib, захотели, чтобы он скопировался просто в some-prj/src. Версия 1.6.8 это не позволяла делать.

Так же несколько утомляет необходимость писать имя копируемого файла и в источнике, и в приемнике для map_file. Т.е., когда несколько раз напишешь что-то вроде e.map_file 'prj/src/h/config.h' => 'h/config.h', то это надоедает.

В связи с этим сделаны наметки версии 1.6.9, в которой реализованы решения для двух вышеуказанных случаев:

MxxRu::arch_externals :libmosquitto do |e|
  e.url 'http://mosquitto.org/files/source/mosquitto-1.4.8.tar.gz'

  e.map_dir 'lib/*' => 'dev/libmosquitto/src'
  e.map_file 'config.h' => 'dev/libmosquitto/*'
end

Т.е. если в параметре src для map_dir последним элементом является звездочка, то считается, что в dst задано новое имя для исходного каталога. В данном примере каталог lib копируется в каталог dev/libmosquitto под именем src.

Если в параметре dst для map_file последним элементом является звездочка, то считается, что имя файла при копировании должно сохраниться. Т.е. в примере выше файл config.h будет скопирован в файл dev/libmosquitto/config.h.

Лично мне пока оба решения нравятся. Вроде бы просто и понятно, плюс совместимость не нарушается. Но это мое мнение. Интересно и другие мнения послушать. Если есть противопоказания, то проще сейчас все переделать, а не после того, как версия 1.6.9 будет зафиксирована.

В общем, если не будет никаких возражений, то через два-три дня версия 1.6.9 с этими двумя нововведениями выйдет в свет.

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

суббота, 26 марта 2016 г.

[prog.flame] Java-программисты боятся, что в Java добавят ключевое слово var

Все-таки люди, программирующие на Java, имеют особый склад ума (что, в принципе, ожидаемо, учитывая свойства этого языка программирования). Иначе сложно объяснить волнения, вызванные намерениями добавить в Java ключевое слово var (например, вот статья с попытками рассмотреть доводы "за" и "против" на Хабре и уже не маленькое обсуждение на LOR-е).

Странные люди. Смотреть нужно в первую очередь на то, что можно получить от автоматического вывода типа локальной переменной. Насколько я помню, именно необходимость такого вывода стала причиной добавления var-ов в C#, т.к. без этого реализация и использование LINQ вряд ли были бы возможны. Да и в C++11, после добавления в язык variadic templates и lambdas без auto уже никуда. Ну вот серьезно, сейчас в C++ я могу написать вот так:

std::thread first;
std::thread second;
std::thread third;
auto thr_joiner = so_5::auto_join(first, second, third);

И, на мой взгляд, это гораздо лучше, чем заставлять программиста писать вот так:

std::thread first;
std::thread second;
std::thread third;
so_5::threads_auto_joiner<3> thr_joiner = so_5::auto_join(first, second, third);

Еще веселее дела обстоят с лямбда-функциями, для которых тип генерируется самим компиляторам и который неизвестен программисту. Ключевое слово auto позволяет вот так:

std::FILE * f = std::fopen(file_name, "r");
if( f ) {
   auto f_closer = at_scope_exit([f]{ std::fclose(f); });
   ...
}

А если бы его не было, как бы пришлось извращаться? Писать что-то вроде:

std::FILE * f = std::fopen(file_name, "r");
if( f ) {
   at_exit_t< std::function<void()> > f_closer = at_scope_exit([f]{ std::fclose(f); });
   ...
}

Как говорится, нет уж, спасибо ;)

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

Так что, на мой взгляд, очень странные обсуждения ведутся в стане Java-программистов. Впрочем, там язык настолько убог, что может var просто поздно добавлять... :)


Касательно auto в C++. До тех пор, пока не работаешь плотно с навороченными шаблонными конструкциями, к auto относишься настороженно. Ведь, действительно, код, в котором сплошные auto, прочитать сложнее, чем код со всеми аннотациями типов. Однако, даже если речь идет о более-менее простых ситуациях, без шаблонных наворотов, то оказывается, что auto может повысить качество и безопасность кода. Взять, скажем, совсем свежий пример:

char *path_name(const struct name_path *path, const char *name)
{
        const struct name_path *p;
        char *n, *m;
        int nlen = strlen(name);
        int len = nlen + 1;

Ведь будь он написан вот в таком виде:

char *path_name(const struct name_path *path, const char *name)
{
        const struct name_path *p;
        char *n, *m;
        auto nlen = strlen(name);
        auto len = nlen + 1;

Менее понятным он бы не стал. А вот надежнее -- наверняка.

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

четверг, 24 марта 2016 г.

[prog.c++11] Дальнейшая диверсификация SObjectizer?

С момента появления mchain-ов в версии 5.5.13 возможности SObjectizer-а по поддержке CSP-like concurrency потихонечку расширяются. Так, в грядущей версии 5.5.16 mchain-ы станут полноценными MPMC-каналами (т.е. сразу несколько нитей смогут читать сообщения из mchain-а). Плюс, конечно же, функция select, которая позволяет выбирать сообщения сразу из нескольких mchain-ов.

В связи с этим уже неправильно позиционировать SObjectizer как только лишь actor framework. Т.к. кроме actor model из коробки уже имеется поддержка и CSP channels.

А раз так, может пойти и еще дальше? И добавить в SObjectizer поддержку цепочек задач? Что-то вроде:

void initiate_image_processing(so_5::environment_t & env, image_params params)
{
   // Готовим цепочку задач и привязываем ее к уже созданному
   // thread_pool-диспетчеру с именем "tasks_pool".
   schedule( env,
      so_5::disp::thread_pool::create_disp_binder("tasks_pool", ...),
      make_task( env, [params]() -> so_5::task< loaded_image > {
         ... // Какие-то действия по загрузке картинки.
         return loaded_image{ ... };
      })
      .then([]( loaded_image & img ) -> so_5::task< prepared_image > {
         ... // Какая-то нехилая обработка.
         return prepared_image{ ... };
      })
      .then([]( prepared_image & img ) -> so_5::task< converted_image > {
         ... // Какая-то еще более нехилая обработка.
         return converted_image{ ... };
      })
      .then([params]( converted_image & img ) {
         ... // Ну совсем замороченная обработка.
         so_5::send< transformed_image >(params.dest(), ...);
      }) );
}

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

Понятное дело, что глубоко в эту тему я не копал. Но, думается, можно сделать что-то вроде Data Flow и Dependency Graphs из Intel-овской Threading Building Blocks или Task Parallelism из Microsoft-овской PPL. Вопрос только в том, нужно/интересно ли это кому-нибудь?

PS. Возможно, все это будет логичным продолжением прототипа для реактивного программирования средствами SO-5, только в другом синтаксисе.