суббота, 18 мая 2019 г.

[prog.c++] Еще один любопытный баг на стыке многопоточности и ООП

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

Итак, обнаружилось, что один из тестов время от времени падает с диагностикой "pure virtual method called". Разбирательство показало, что проблема проявляется в коде, который похож вот на этот (лишние детали убраны, дабы не можно было рассказывать только о сути проблемы):

class data_owner_t {
public:
   virtual void update() = 0;
   ...
};

class data_repository_t {
   std::mutex lock_;
   some_container_t<data_owner_t *> owners_;
   ...
public:
   void add(data_owner_t & owner) {
      std::lock_guard lock{lock_};
      owners_.insert(&owner);
   }

   void remove(data_owner_t & owner) {
      std::lock_guard lock{lock_};
      owners_.erase(&owner);
   }

   void update_all() {
      std::lock_guard lock{lock_};
      for(auto * p : owners_)
         p->update();
   }
   ...
};

Виртуальный метод здесь всего один -- это data_owner_t::update. Вызывается он только внутри data_repository_t::update_all, в цикле, перебирающем всех зарегистрированных owner-ов. Значит в какой-то момент времени внутри data_repository_t оказывается невалидный указатель на owner-а. Но как и почему?

среда, 15 мая 2019 г.

[work.thoughts] Теплое чувство внутри, большое видится на расстоянии и периодическое удивление...

...тому, что наши разработки кто-то берет и использует.

Работаю сейчас над сопроводительными материалами к очередному релизу SObjectizer-а. Для чего перечитываю статью Павла Вайнермана "Если проект «Театр», используй акторов…", в которой речь идет об опыте применения SObjectizer-а для управления сценическим оборудованием в театре. И вот на чтении вот этого фрагмента меня вдруг "пробивает":

Был разработан «проигрыватель сценариев» который создаёт группу специальных акторов и запускает их в работу. Мы разработали два вида акторов: акторы-исполнители, предназначенные для выполнения задания для конкретного штанкета и актор-координатор, который распределяет задания между исполнителями. Причём акторы-исполнители создаются по мере необходимости, если в момент очередной команды не находится свободного. За создание и поддержание пула акторов-исполнителей отвечает актор-координатор. В итоге управление выглядит примерно следующим образом:

  • оператор загружает сценарий;
  • «перелистывает» его до нужной повестки (обычно просто идёт подряд);
  • в нужный момент нажимает кнопку «приготовиться» по которой актору-координатору присылаются команда (сообщение) по каждому штанкету входящему в текущую повестку с параметрами движения;
  • актор-координатор смотрит свой пул свободных акторов-исполнителей, берёт свободного (если нет создаёт нового) и передаёт ему задание (номер штанкеты и параметры движения);
  • каждый актор-исполнитель получив задание начинает отрабатывать команду «приготовиться». Т.е. подключает двигатель и переходит в режим ожидания команды «поехали»;
  • когда настаёт время, оператор подаёт команду «поехали»;
  • команда «поехали» приходит координатору. Он рассылает её всем своим задействованным в текущий момент исполнителями и они начинают «исполнение».

Тут стоит отметить, что в повестке встречаются дополнительные параметры. Например начать движение с задержкой N секунд или начинать движение только после отдельной специальной команды оператора. Поэтому список состояний у каждого актора-исполнителя достаточно большой: «готов к выполнению очередной команды», «готов к движению», «задержка движения», «ожидание команды оператора», «движение», «исполнение завершено», «сбой в работе».

Почему-то именно при перечитывании этого фрагмента до меня внезапно (с) дошло, что вообще-то говоря, выбор SObjectizer-а для реализации этого всего был вовсе не обязательным. И это мягко говоря.

В принципе мы, разработчики, с пиететом относимся к инструментам от больших компаний. И это нормально. Если небезосновательное мнение, что в больших софтверных компаниях, вроде Google, Facebook, Amazon, Microsoft, Яндекс, Лаборатория Касперского и т.д., оказываются очень квалифицированные разработчики. Которым, при этом, создают отличные условия для концентрации именно на разработке софта.

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

Поэтому нет ничего удивительного, когда разработчики берут proxygen от Facebook или Abseil от Google. Просто потому, что это инструменты от Facebook-а и Google. Само их применение в проектах компаний таких масштабов уже служит неким знаком качества.

А вот когда для выполнения непростого и ответственного проекта выбирается кустарная разработка от никому неизвестной провинциальной конторы, грубо говоря, каких-то "Рогов и копыт", то вот это доставляет. И вызывает теплое чувство внутри.

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

При этом, хоть описанный в статье проект далек от сложности и критичности от, скажем, системы управления Boeing 737 Max, но это вовсе не "Hello, World". Мягко говоря. И не вебня уровня какого-нибудь Интернет-форума, в котором недоступность или ограниченная функциональность в течении десятков минут не страшна от слова совсем. Вполне себе реальное оборудование и стоимость отказа в неподходящий момент высокая. И разработчики сочли возможным использовать наш продукт, посчитав его достаточно качественным, зрелым и обеспеченным должной поддержкой.

А ведь запросто могли и не счесть. Но сочли. И вот когда осознание этого факта догоняет (а догоняет-то не сразу), то что-то в голове щелкает. До дрожи в коленках ;) Не зря, получается, мы все это делали. Не зря.

Ну и отдельно хочется сказать спасибо всем innovator-ам и early adopter-ам, которые рискуют выбирать наши продукты на свой страх и риск. То, что вы делаете доказывает, что есть таки смысл в том, что делаем мы.

PS. Кстати говоря, то факт, что и SObjectizer, и RESTinio справляются с возложенными на них задачами, меня лично вовсе не удивляет. Я не из тех персонажей из анекдота "Да вы успокойтесь, софт для этого самолета делала наша фирма, поэтому он даже не вырулит на взлетную полосу". Все-таки мы делаем то, что работает. А то, что не работает, стараемся оперативно допиливать напильником ;)

[prog.c++] Обновили RESTinio до версии 0.4.9

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

Пару слов о текущем статусе разработки RESTinio.

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

Поэтому если перед кем-то стоит выбор брать RESTinio в работу или не брать, то ответ, на наш взгляд, очевиден: конечно же брать. Без поддержки мы вас не оставим :)

Попутно просьба поделиться своими впечатлениям тех, кто смотрел на RESTinio и не выбрал его. Почему? Чего не хватило? Что отпугнуло?

Эта информация сильно поможет нам сделать RESTinio еще лучше и практичнее.

Так же не могу не дать ссылку на свежую статью на Хабре о том, как можно использовать архитектурные особенности RESTinio для длительной обработки запросов: "RESTinio — это асинхронный HTTP-сервер. Асинхронный".