Мы обновили свою легковесную библиотеку для работы с отложенными и периодическими таймерами (wallclock-таймеры не поддерживаются в принципе). В этой версии добавлены две важные фичи:
1. Раньше действие для таймера всегда имело тип std::function<void()>
, что было гибко и удобно, но имело скрытые накладные расходы, связанные с std::function (по сути, std::function тут выступал как умный указатель для лямбд и функторов). Если от этих скрытых расходов хочется избавиться, то можно задать свой собственный тип. Например:
class operation_canceler {
operation_manager & manager_;
operation_id id_;
public:
operation_canceler(operation_manager & manager, operation_id id)
: manager_{manager}, id_{id}
{}
void operator()() const noexcept
{
manager_.cancel(id_);
}
};
...
// Define type of timer thread which was use operation_canceler as
// a timer action type.
using my_timer_wheel_thread = timertt::timer_wheel_thread_template<
operation_canceler,
timertt::default_error_logger,
timertt::default_actor_exception_handler >;
...
// Create and use this timer thread.
my_timer_wheel_thread tt;
tt.start();
...
tt.activate( std::chrono::milliseconds(750), operation_canceler{manager, current_id});
Тип должен быть Moveable и MoveConstructible. Соответственно, теперь когда создается объект-таймер, там резервируется место для пользовательского объекта-функтора. А при активации таймера пользовательский функтор мувится в этот зарезервированный кусок памяти. Тем самым не происходит дополнительных аллокаций памяти (как это временами может происходить с std::function).
2. Теперь пользователь сам может создавать объекты-таймеры на стеке или внутри других своих объектов. Ранее объекты-таймеры создавались исключительно динамически. Теперь можно избежать дополнительных аллокаций, но зато пользователь сейчас сам должен следить за тем, чтобы таймер не закончил свою жизнь раньше времени. Например:
void do_something_complex() {
timertt::default_timer_wheel_thread tt;
tt.start();
...
timertt::default_timer_wheel_thread::scoped_timer_object timer;
// Activate
tt.activate(timer, std::chrono::milliseconds(250), ...);
...
// Timer can be deactivated in usual way.
tt.deactivate(timer);
...
tt.shutdown_and_join();
}
Правда, в этой версии мы несколько сломали совместимость на уровне исходного кода. Поэтому номер версии 1.2.0, а не 1.1.4.
Пару слов о происхождении и назначении библиотеки. Когда-то мы долго и с удовольствием использовали большую библиотеку ACE. В том числе и тамошние таймеры (реализация которых была добротной и продвинутой). Но по мере перехода на C++11 мы постепенно отказывались от ACE и в один прекрасный момент оказалось, что из ACE нам нужны только таймеры. Чтобы не таскать дистрибутив ACE только ради таймеров, мы сделали свою легковесную header-only либу, которая базируется только на штатных возможностях C++11.
У нас timertt в работе уже года три. Проблем не замечено. Работает стабильно, может поддерживать изрядное количество таймеров (десятки и сотни миллионов). Реализует три разных таймерных механизма: wheel, heap и list, каждый из которых хорош в своей ситуации.
Предыдущие версии timertt могли работать и с компиляторами, которые не очень хорошо поддерживали C++11 (в частности, VS2013). Начиная с 1.2.0 мы на такие компиляторы уже не оглядываемся. Нужно что-то более-менее нормальное (gcc 4.8-7.2, clang 3.5-5.0, vs2015/2017). Однако, основная часть кода пока еще под все возможности C++ (вроде noexcept и constexpr там, где это разумно) еще не адаптирована. Сделаем это со временем.
Так же отметим, что новые фичи были только-только добавлены. Наверняка что-то можно улучшить и сделать удобнее. Это мы так же сделаем со временем, а если будет положительный фидбэк, то это произойдет быстрее.
Архивы с исходниками библиотеки можно найти здесь. Сами исходники живут здесь. Документация здесь.
Лицензия: BSD-3-CLAUSE.
Disclaimer: если вы уже используете таймеры, которые предоставляют такие инструменты, как ACE, asio, libuv, Qt и пр., то вряд ли вам нужна timertt. А вот если вам потребовалось в программе работать с отложенными или периодическими действиями, а тащить в проект ACE/asio/libuv, которых там не было... Или если у вас миллионы таких действий, то вот тогда timertt вам может помочь. В общем, для большинства — это образцовое ненужно. Но вот нам потребовалось, может кому еще пригодится.
ЗЫ. Если кому-то интересно, то самый первый анонс timertt вызвал забавный срач.