Дабы выбросить из своего проекта ACE Framework пришлось сделать свою реализацию таймеров. Получилась небольшая библиотека, которая не имеет внешних зависимостей и использует только возможности стандартной библиотеки C++11. Проверялась под Windows (MSVC++2013, MinGW-w64 GCC 4.9.1) и Linux (GCC 4.9.1).
Лицензия: 3-х секционная BSD. Т.е. использоваться может без проблем как в открытых, так и в закрытых проектах.
Библиотека поддерживает только таймеры на основе тайм-аутов, т.е. таймеры, которые должны сработать через сколько-то миллисекунд (секунд, минут и т.д.) после момента активации таймера. wallclock-таймеры не поддерживаются.
Таймеры могут быть однократными (срабатывают всего один раз, после чего деактивируются), либо периодическими (повторяются до тех пор, пока не будут явно деактивированы или пока таймерная нить не завершит свою работу).
Библиотека поддерживает три таймерных механизма: timer_wheel, timer_heap и timer_list, у каждого из которых есть свои преимущества и недостатки. Может поддерживаться большое количество таймеров (сотни тысяч, миллионы или даже десятки миллионов) и обеспечивается высокая скорость обработки таймеров (до нескольких миллионов в секунду, но это зависит от времени работы связанных с таймером пользовательских событий).
В коде все это выглядит приблизительно следующим образом:
#include <iostream>
#include <cstdlib>
#include <timertt/all.hpp>
using namespace std;
using namespace std::chrono;
using namespace timertt;
int main()
{
timer_wheel_thread_t tt;
// Timer thread must be started before activation of timers.
tt.start();
// The simple single-shot timer.
tt.activate( milliseconds( 20 ),
[]() { cout << "Simple one-shot" << endl; } );
// The simple periodic timer.
// Will work until timer thread finished.
tt.activate( milliseconds( 20 ), milliseconds( 20 ),
[]() {
static int i = 0;
cout << "Simple periodic (" << i << ")" << endl;
++i;
} );
// Allocation of timer and explicit activation.
auto id1 = tt.allocate();
tt.activate( id1, milliseconds( 30 ),
[]() {
cout << "Preallocated single-shot timer" << endl;
} );
// Periodic timer with timer preallocation, explicit activation
// and deactivation from the timer action.
auto id2 = tt.allocate();
tt.activate( id2, milliseconds( 40 ), milliseconds( 15 ),
[id2, &tt]() {
static int i = 0;
cout << "Preallocated periodic (" << i << ")" << endl;
++i;
if( i > 2 )
tt.deactivate( id2 );
} );
// Single-shot timer with explicit activation and deactivation
// before timer event.
auto id3 = tt.allocate();
tt.activate( id3, milliseconds( 50 ),
[]() {
cerr << "This timer must not be called!" << endl;
std::abort();
} );
tt.deactivate( id3 );
// Wait for some time.
this_thread::sleep_for( milliseconds( 200 ) );
// Finish the timer thread.
tt.shutdown_and_join();
}
Скачать можно с SourceForge: только header-only вариант или же полный вариант с тестами/примерами. Документация там же в Wiki (пока на русском языке, потихоньку будет переводиться на английский).
Еще чуть-чуть подробностей по релизу здесь.
Сразу поясню для желающих спрашивать «нафига это нада?» и/или «афтар, а чем это лучше/хуже?». Если вы в своем проекте уже используете какой-то фреймворк/библиотеку, предоставляющий таймеры (например, ACE/Boost/Qt/wxWidgets/libuv/libev/libevent/you-name-it), то, скорее всего, timertt вам не нужен. Если только вы не обнаружите, что ваш инструмент не очень хорошо справляется с миллионом таймеров или же вам надоело натягивать свою прикладную логику на API вашего инструмента (актуально, например, для ACE, где таймерные очереди реализованы здорово, на вот API для них несколько своеобразный и не всегда удобный).
Если же в вашем проекте никаких тяжеловесных зависимостей нет, а таймеры нужны, то можно и в сторону timertt посмотреть.
Ну а вообще делал для себя, но не вижу причин не выложить в виде OpenSource.