A C++ class that wraps Win32 waitable timers.
by
Dr. Thomas Becker
tmbecker@compuserve.com
COPYRIGHT (C) 1997 Thomas BeckerPERMISSION NOTICE:
PERMISSION TO USE, COPY, MODIFY, AND DISTRIBUTE THIS SOFTWARE FOR ANY PURPOSE AND WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT ALL COPIES ARE ACCOMPANIED BY THE COMPLETE MACHINE-READABLE SOURCE CODE, ALL MODIFIED FILES CARRY PROMINENT NOTICES AS TO WHEN AND BY WHOM THEY WERE MODIFIED, THE ABOVE COPYRIGHT NOTICE, THIS PERMISSION NOTICE AND THE NO-WARRANTY NOTICE BELOW APPEAR IN ALL SOURCE FILES AND IN ALL SUPPORTING DOCUMENTATION.
NO-WARRANTY NOTICE:
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
The CWaitableTimer class wraps the Win32 waitable timer object. Here, timers are restricted to non-periodic having no completion routine. The reason for providing this wrapper is to make it easier to switch to a substitute when working with NT version 3.51 or less. Waitable timers did not become available until version 4.0.
The constructor creates a waitable timer. The Set member function activates the timer, causing it to become signaled after the specified amount of time.
Example:
CWaitableTimer someTimer ; someTimer.Set(3000) ;Three seconds later, the handle that is returned by someTimer.GetHandle() will become signaled.
When the Set member function is called again while the timer is active and waiting for the time period to elapse, the handle is not signaled and the time interval starts over again.
When the Cancel member function is called while the timer is active and waiting for the time period to elapse, the timer enters the inactive state without signaling the handle.
Note: When you try to call the Set or Cancel member functions while the timer is active, it can never be guaranteed that the time interval does not complete and the handle does not get signaled before Set or Cancel get a chance to interrupt the timer. The Set member function always resets the handle to the non-signaled state. The Cancel member function, by contrast, does not affect the state of the handle at all.
The constructor does not perform any error checking. The Set and Cancel member functions throw a CWin32Exception with error code ERROR_INVALID_HANDLE if they find that the constructor failed to create the timer.
If the destructor encounters an error, it throws a CWin32Exception but does not propagate it.
CWaitableTimer | Constructs a CWaitableTimer object. |
Set | Sets the timer. |
Cancel | Cancels the timer. |
GetHandle | Returns a handle to the timer object. |
CWaitableTimer::CWaitableTimer( BOOL bManualReset // = FALSE, manual reset timer );
void CWaitableTimer::Set( DWORD dwMilliSeconds // timer interval );
CWaitableTimer::Cancel( );
When the function catches the timer in the active state while it is waiting for the time period to elapse, the wait is abandoned and the handle is not signaled.
When the function catches the timer in the inactive state, the cancel operation has no effect.
HANDLE CWaitableTimer::GetHandle( );
Win32Exception.h also contains the declaration of a class named CSehException, which can be used to catch operating system exceptions (SEH-exceptions) such as access violations via the C++ exception handling mechanism. See the documentation of the _set_se_translator() function and the article "Structured exception handling" in the C++ Language Reference for a detailed explanation.
#include<windows.h> #include<iostream.h> #include<conio.h> #include"Win32Exceptions.h" #include"WaitableTimer.h" // Manual reset timer CWaitableTimer cTimer(FALSE) ; // Thread function that waits on timer // DWORD WINAPI Waiter(DWORD) { while (1) { WaitForSingleObject(cTimer.GetHandle(), INFINITE) ; Beep(300, 100) ; } return 0 ; } /////////////////////////////////////////////////////////////// // // main // void main() { try { // Create waiter thread // DWORD dwThreadId ; CreateThread( NULL, // pointer to thread security attributes 0, // initial thread stack size, in bytes (LPTHREAD_START_ROUTINE) Waiter, // thread function 0, // argument for new thread 0, // creation flags &dwThreadId // pointer to returned thread identifier ); // Start and cancel timer according to user input // cout << "Thread ID: " << dwThreadId << "\n" << "Enter s to set, c to cancel, ESC to quit:\n" << flush ; char c = getche() ; cout << "\n" << flush ; // while (27 != c) { switch (c) { case 's': cTimer.Set(2000) ; break ; case 'c': cTimer.Cancel() ; ResetEvent(cTimer.GetHandle()) ; break ; } c = getche() ; cout << "\n" << flush ; } } catch(CWin32Exception& eWin32) { cout << "Exception:\n" << "Error code: " << eWin32.GetErrorCode() << "\nFile: " << eWin32.GetFileName() << "\nLine: " << eWin32.GetLineNo() << "\nPress any key to continue." << flush ; getche() ; } }