вторник, 25 ноября 2014 г.

[prog.c++] Версия 1.1.0 библиотеки timertt

Библиотека timertt обновилась до версии 1.1.0.

В двух словах, timertt -- это:

Header-only библиотека без внешних зависимостей, базирующаяся на возможностях стандартной библиотеки C++11. Реализует таймеры на основе тайм-аутов, т.е. таймеры, которые должны сработать через сколько-то миллисекунд (секунд, минут и т.д.) после момента активации таймера. wallclock-таймеры не поддерживаются.

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

Библиотека поддерживает три таймерных механизма: timer_wheel, timer_heap и timer_list, у каждого из которых есть свои преимущества и недостатки. Может поддерживаться большое количество таймеров (десятки и сотни миллионов) и обеспечивается высокая скорость обработки таймеров (до нескольких миллионов в секунду).

Кросс-платформенная, проверялась посредством MSVS2013 (Windows), GCC 4.9 (Windows, Linux), Clang 3.5 (Linux).

Распространяется под 3-х секционной BSD-лицензией, может свободно использоваться как в открытых, так и в закрытых коммерческих проектах.

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

Вот так может выглядеть работа с таймерами посредством timer_manager:

using namespace std;
using namespace chrono;
using namespace timertt;

timer_heap_manager_template< thread_safety::unsafe > tm;

tm.activate( milliseconds(100), []{ cout << "hello!" << endl; } );
tm.activate( milliseconds(200), []{ cout << "hello!" << endl; } );

auto stop_point = system_clock::now() + milliseconds(300);
while( stop_point > system_clock::now() )
{
  tm.process_expired_timers();
  this_thread::sleep_for(
        tm.timeout_before_nearest_timer( milliseconds(10) ) );
}

А вот, для сравнения, аналогичный код, использующий timer_thread:

using namespace std;
using namespace chrono;
using namespace timertt;

timer_heap_thread_t tt;

tt.start();

tt.activate( milliseconds(100), []{ cout << "hello!" << endl; } );
tt.activate( milliseconds(200), []{ cout << "hello!" << endl; } );

this_thread::sleep_for( milliseconds(300) );

tt.shutdown_and_join();

Новые timer_manager-ы могут иметь или не иметь средств защиты от многопоточности. Не защищенные от многопоточности timer_manager-ы предназначены для использования в однопоточных приложениях, где вообще все операции выполняются на контексте одной нити. Тогда как защищенные от многопоточности thread_manager-ы позволяют создавать и удалять таймеры из разных нитей. Но обработка таймеров (т.е. вызовы методов process_expired_timers и nearest_time_point/timeout_before_nearest_timer) должна выполняться всего одной нитью.

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

timer_heap_manager_template< thread_safety::unsafe > tm(...);
app_event_queue eq(...);
mosqpp::mosquittopp mosq(...);
...
while(true)
{
  // Process application events while they exist...
  while( !eq.empty() )
  {
    process_app_event( eq.pop() );
    // All expired timers can be handled.
    tm.process_expired_timers();
  }

  // Process any MQTT-related events.
  auto r = mosq.loop(
    // Wait no more time than next timer event.
    to_milliseconds( tm.timeout_before_nearest_timer( millisecons(1000) ) ) );
  if( r != MOSQ_ERR_SUCCESS )
    ... // Some error handling.
}

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

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

Комментариев нет: