1
\$\begingroup\$

I have a Visual Studio 2008 C++03 project where I need a timer. I have an implementation that works well, but I'd like any general suggestions from the community on how to improve it. (More generic, lower cost of creating timers, etc...)

class Timer
{
public:
    typedef boost::function< void( ) > OnTimer;

    Timer( const OnTimer& f, DWORD timeout )
        : cancel_event_( ::CreateEvent( NULL, FALSE, FALSE, NULL ), ::CloseHandle ),
          timer_thread_( boost::bind( &Timer::TimerThread, cancel_event_.get(), f, timeout ) ),
          timeout_( timeout )
    {
    };

    ~Timer() { ::SetEvent( cancel_event_.get() ); };

    DWORD Timeout() const { return timeout_; };

private:

    static void TimerThread( HANDLE cancel_event, const OnTimer& f, DWORD timeout )
    {
        if( WAIT_OBJECT_0 != ::WaitForSingleObject( cancel_event, timeout ) )
            f();
    };

    /// time to wait for the timer to fire
    UINT timeout_;
    /// event signaled when the timer should be canceled
    boost::shared_ptr< void > cancel_event_;
    /// thread that runs the timer (similar to boost::thread, but doesn't require `localtime`, `gmtime`, or `abort`)
    util::CThread timer_thread_;
}; // class Timer

Preemptive:

  • My project does not have a window message pump so SetTimer is unsuitable.
  • I do not want to incur the cost of importing the mmtimer library.
  • I can only use boost header libraries, therefore boost::timer is unsuitable.
  • I would prefer to keep the discussion limited to this block of code.
\$\endgroup\$
2
\$\begingroup\$

I think that you can create one thread to handle all timers. When a new timer is created, you should add it in a (synchronized) queue of "timers to trigger". The background thread must wait for the closest timer to be triggered. Also you should wake it up each time you modify the queue of timers and recalculate "which is the closest timer now?".

When the queue is empty, the background thread can be destroyed (joined) or you can wait an "exit" event (or the creation of another timer). Those are just details. The background thread can be created by the first timer and joined when the last timer is destroyed, or it can just live in the whole program execution.

Another thing, to improve portability you could use boost::thread library and boost's condition variables instead of raw Windows events.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.