вторник, 1 января 2030 г.

О блоге

Более двадцати лет я занимался разработкой ПО, в основном как программист и тим-лид, а в 2012-2014гг как руководитель департамента разработки и внедрения ПО в компании Интервэйл (подробнее на LinkedIn). В настоящее время занимаюсь развитием компании по разработке ПО stiffstream, в которой являюсь одним из соучредителей. Поэтому в моем блоге много заметок о работе, в частности о программировании и компьютерах, а так же об управлении.

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

понедельник, 31 декабря 2029 г.

[life.photo] Характерный портрет: вы и ваш мир моими глазами. Безвозмездно :)

Вы художник? Бармен или музыкант? Или, может быть, коллекционер? Плотник или столяр? Кузнец или слесарь? Владеете маленьким магазинчиком или управляете большим производством? Реставрируете старинные часы или просто починяете примус? Всю жизнь занимаетесь своим любимым делом и хотели бы иметь фото на память?

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

среда, 1 июля 2020 г.

[prog.flame] Может уже и пришло время закапывать C++, но пока он позволяет в коде выписывать ABNF грамматики...

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

Иногда складывается впечатление, что эти стенания повсюду. Особенно на профильных ресурсах, типа Reddit, LOR, RSDN (может и на Хабре, но до Хабра сейчас просто уже руки не доходят).

Финальным гвоздем стали очередные вбросы в Telegram канале C++ Russia от известного своим праздным звездежом хаскелиста Александра Гранина, у которого, походу, второй натурой стал троллинг C++а и C++ников. С традиционным уже участием на C++ Russia с докладом про функциональщину.

В общем, послушать активно испражняющихся в Интернетах специалистов по всем вопросам на свете и может показаться, что хуже C++ только мучительная смерть от бубонной чумы. Да и то не факт.

В тоже самое время этот самый современный C++, в который, как искренне верят неасиляторы, напихали всякой ненужной чуйни, лично мне позволяет в декларативном виде записывать в коде ABNF грамматики из RFC по HTTP/1.1.

Причем это даже не самый еще современный C++, а всего лишь C++14.

И что-то мне подсказывает, что сделать подобное на каких-то "типа альтернативах" C++ будет не так уж и просто. Особенно с учетом накладных расходов в run-time. Если вообще возможно.

Ну а вот и сам упомянутый фрагмент. Который отвечает за парсинг содержимого HTTP-заголовка Transfer-Encoding согласно спецификации.

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

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

Фильмы

В погоне за ветром (Ride Like a Girl, 2019). Отлично снятый байопик. Добрый, жизнеутверждающий. Мне понравился.

Идеальный дворец Фердинанда Шеваля (L'incroyable histoire du facteur Cheval, 2018). Странный фильм про странного человека. Снят хорошо. Но смотреть тяжело. История рассказана трогательная, хотя и очень печальная.

Афера в Майами (Wasp Network, 2019). Просто удивительно, как из такой интересной и многослойной истории получилось такое унылое и затянутое непонятно что. Хорошо хоть, что снято красиво.

Отверженные (Les misérables, 2019). У фильма высокие оценки, но мне было смотреть не интересно. Ни сюжет не зацепил, ни актеры. А операторская работа так вообще раздражала. Сложилось ощущение, что фильм ценен разве что за остросоциальную тему, но вовсе не как художественное произведение.

Сериалы

Настоящий детектив (True Detective), второй сезон. Как по мне, так совершенно не похож на первый. Посмотрел из-за отсутствия каких-то других достойных вариантов. Не могу сказать, что мне понравилось. Не понял, на что режиссер пытался сделать акцент: на социальной составляющей, на атмосфере, на сюжете или же на чем-то еще. Как по мне, так рядовое и проходное кино. Когда выбора нет, можно и посмотреть.

Обвиняемый (Presunto culpable, 2018). Начал смотреть из-за исключительно красивого видеоряда в трейлере. Ну и досматривал тоже исключительно из-за работы оператора. Сам по себе сериал туфта, все события из 13 серий можно было бы запросто уместить в 3-4 и получилось бы динамичнее и напряженнее. Но вот работа оператора -- это что-то. В некоторых местах картинку хотелось останавливать и печатать, чтобы на стену повесить. Компоновка кадров, работа со светом и даже разумное использование светосильной оптики вызывает мое почтение.

Ночной администратор (The Night Manager, 2015). Актеры хорошие, на них приятно смотреть. А вот сам фильм не зацепил.

среда, 24 июня 2020 г.

[prog.c++] Максимальное значение времени, которое можно передать в std::condition_variable::wait_for

Метод std::condition_variable::wait_for в качестве одного из параметров получает время ожидания срабатывания condition_variable. На cppreference.com этот параметр называется rel_time. И про его значение сказано следующее:

an object of type std::chrono::duration representing the maximum time to spend waiting. Note that rel_time must be small enough not to overflow when added to std::chrono::steady_clock::now().

Ok. Значит значение rel_time не должно быть таким, чтобы вызвать переполнение, когда его суммируют с std::chrono::steady_clock::now(). Но каким же оно тогда может быть?

В принципе, можно предположить, что максимально допустимое значение для rel_time может быть получено таким нехитрым способом:

std::chrono::steady_clock::time_point::max() - std::chrono::steady_clock::now()

Т.е. оно не должно быть больше разницы между самой большой меткой времени, которую можно выразить в std::chrono::steady_clock, и текущей меткой времени.

Вроде бы так. Но не все так просто, ведь мы же в мире C++.

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

Так вот под Windows и VC++19 (и под FreeBSD и clang) получается вполне себе ожидаемый результат:

wait_time: 9222236437359ms, days: 1
wait for: 1001ms

А вот под Linux-ом и GCC/clang меня ждет неожиданное открытие:

wait_time: 9223171751593ms, days: 1
wait for: 0ms
wait_time: 9136771751593ms, days: 1001
wait for: 0ms
wait_time: 9050371751593ms, days: 2001
wait for: 0ms
wait_time: 8963971751593ms, days: 3001
wait for: 0ms
wait_time: 8877571751593ms, days: 4001
wait for: 0ms
wait_time: 8791171751593ms, days: 5001
wait for: 0ms
... skipped
wait_time: 7840771751592ms, days: 16001
wait for: 0ms
wait_time: 7754371751592ms, days: 17001
wait for: 0ms
wait_time: 7667971751592ms, days: 18001
wait for: 0ms
wait_time: 7581571751592ms, days: 19001
wait for: 1000ms

Т.е. мало того, что нельзя просто взять разность между (time_point::max() - time_point::now()) и для безопасности отнять оттуда какую-то разумную дельту (вроде 24 часов). Эту самую дельту нужно сделать весьма большой.

Почему так -- я хз. Вероятно какие-то фокусы трансформации вызова condition_variable::wait_for в POSIX-овый вызов. Но вот на практике довелось в это стукнуться.

PS. Зачем может потребоваться задавать большие значения для rel_time? Бывают случаи, когда либо пользователь задает время ожидания какого-то события, либо же нужно ждать "когда рак на горе свиснет". И если мы хотим время ожидания представить в программе всего одним значением std::chrono::duration, которое можно будет просто без дополнительных проверок отдать в condition_variable::wait_for (или не делать отдельно вызовы condition_variable::wait и condition_variable::wait_for), то нужно понимать, какая именно величина будет означать "когда рак на горе свиснет".

понедельник, 22 июня 2020 г.

[prog.c++] Релиз SObjectizer-5.7.1 и so5extra-1.4.1

Нашлось время и ресурсы запилить новые версии SObjectizer и so5extra.

В SObjectizer-5.7.1 реализовано несколько полезных нововведений и исправлено несколько косяков, которые пока еще не проявлялись.

Одно из самых важных изменений в SObjectizer-5.7.1 -- это возможность назначать лимиты для сообщений по умолчанию:

class demo final : public so_5::agent_t
{
public:
   demo(context_t ctx)
      : so_5::agent_t{ctx
         + limit_then_drop<msg_A>(100u)
         + limit_then_abort<msg_B>(10u)
         // That limit will be used for all other messages.
         + limit_then_drop<any_unspecified_message>(50u)
         }
   {}

   void so_define_agent() override
   {
      // Explicitly defined limit will be used.
      so_subscribe_self().event([](mhood_t<msg_A> cmd) {...});

      // A new limit object will be created for msg_C here.
      so_subscribe_self().event([](mhood_t<msg_C> cmd) {...});
   }
};

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

Второе полезное нововведение в SO-5.7.1 -- это шаблонная функция make_agent_ref, которая позволяет гарантировать нужное время жизни указателя на агента, если этот указатель приходится отдавать в какой-нибудь коллбэк:

class io_performer final : public so_5::agent_t
{
   asio::io::tcp::socket connection_;
   std::array<std::byte, 4096> input_buffer_;

   void handle_incoming_data(std::size_t bytes_transferred) {...}

   void on_some_event(mhood_t<some_msg> cmd)
   {
      // It's time to read some data.
      connection_.async_read_some(asio::buffer(input_buffer_),
         [self=so_5::make_agent_ref(this)]
         (const asio::error_code & ec, std::size_t bytes_transferred)
         {
            if(!ec)
               self->handle_incoming_data(bytes_transferred);
         });
   }
   ...
};

Полный перечень нововведений и изменений в SO-5.7.1 можно найти здесь.

В so5extra-1.4.1 был добавлен новый тип диспетчера: asio_one_thread.

Этот диспетчер использует отдельную рабочую нить, на которой запускается io_context::run и на которой обслуживаются как I/O-операции, так и события привязанных к этому диспетчеру агентов.

По своей логике работы asio_one_thread очень похож на asio_thread_pool диспетчер, но имеет более простую реализацию. И он более удобен в использовании, когда все I/O-операции нужно "прибить" к одному контексту.

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


Хочу поблагодарить всех, кто выбрал SObjectizer/so5extra. Ваш интерес к этим проектам является самым важным стимулом для дальнейшего развития SObjectizer-а. А ваша обратная связь позволяет добавлять в SObjectizer/so5extra функциоальность, до который мы сами бы и не дошли. Что делает SObjectizer/so5extra полезными еще большему кругу разработчиков.

суббота, 20 июня 2020 г.

[prog.thoughts] Применимость вложенных классов в C++ и серьезность проблемы с forward declaration для них

На RSDN-е угораздило пообщаться с персонажем, насколько уверенном в собственном непогрешимом мнении, что просто караул. К счастью, в Интернетах такие на 100% правые люди встречаются гораздо чаще, чем в реальной жизни. А то работать было бы тяжело.

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

Итак, речь пойдет о применимости вложенных классов в C++. И, немного, о том, насколько в реальности серьезна проблема невозможности forward declaration для вложенных классов. Все нижеизложенное является моим имхо, сформулированным после небольшого обдумывания данной темы. Наверняка я в чем-то не прав, поэтому все написанное ниже стоит воспринимать просто как мнение одного конкретного старого C++ника, а не истину в последней инстанции. Если же я забыл описать какой-то важный и интересный сценарий использования вложенных классов, то об этом можно (и даже нужно) написать в комментариях.