A C++ class that provides the functionality of a non-periodic
waitable timer without completion routine.
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 constructor starts a thread that waits on a start event. The Set member function sets this start event. That causes the thread to become active, i.e., to wait for the time interval specified by the Set member function. After this time interval has elapsed, the thread sets an alarm event. The alarm event can be obtained by means of the GetHandle member function. Whether the alarm event is an auto reset or manual reset event is specified in the constructor call. Each time the Set function is called, the alarm event is reset to the non-signalled state.
Example:
CWaitableTimerSubst someTimer ; someTimer.Set(3000) ;Three seconds later, the event that is returned by someTimer.GetHandle() will be set.
When the Set member function is called again while the timer is active and waiting for the time period to elapse, the alarm event is not set 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 setting the alarm event.
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 alarm event does not get set before Set or Cancel get a chance to interrupt the timer. The Set member function always resets the alarm event to the non-signaled state. The Cancel member function, by contrast, does not affect the state of the alarm event 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 an event or thread.
If the destructor encounters an error, it throws a CWin32Exception but does not propagate it.
CWaitableTimerSubst | Constructs a CWaitableTimerSubst object. |
Set | Sets the timer. |
Cancel | Cancels the timer. |
GetHandle | Returns a handle to the alarm event. |
CWaitableTimerSubst::CWaitableTimerSubst( BOOL bAlarmEventManual // = FALSE, manual reset alarm event );
void CWaitableTimerSubst::Set( DWORD dwMilliSeconds // timer interval );
CWaitableTimerSubst::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 alarm event is not set.
When the function catches the timer in the active state after the time period has elapsed, the cancel operation has no effect. The same is true when the timer is caught in the inactive state.
HANDLE CWaitableTimerSubst::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"WaitableTimerSubst.h" // Timer with auto reset alarm event CWaitableTimerSubst 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() ; } }