CWaitableTimerSubst

A C++ class that provides the functionality of a non-periodic waitable timer without completion routine.
by
Dr. Thomas Becker
tmbecker@compuserve.com


Contents

  1. Copyright and Permission Notice
  2. Overview of CWaitableTimerSubst
  3. CWaitableTimerSubst Public Members
  4. CWaitableTimerSubst Exception Handling
  5. CWaitableTimerSubst Example

Copyright and Permission Notice

COPYRIGHT (C) 1997 Thomas Becker

PERMISSION 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.

Overview of CWaitableTimerSubst

class CWaitableTimerSubst

The CWaitableTimerSubst class provides the functionality of non-periodic Win32 waitable timers without completion routine until such time as these become available in Visual C++ under NT.

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 Public Members

Enums Construction
CWaitableTimerSubst Constructs a CWaitableTimerSubst object.
Operations
Set Sets the timer.
Cancel Cancels the timer.
GetHandle Returns a handle to the alarm event.

CWaitableTimerSubst::CWaitableTimerSubst

The CWaitableTimerSubst default constructor creates the thread and the alarm event as well as the internal synchronization objects.
CWaitableTimerSubst::CWaitableTimerSubst( 
  BOOL bAlarmEventManual // = FALSE, manual reset alarm event
  );

Parameters

bAlarmEventManual
Indicates if the alarm event should be a manual reset event.

Remarks

After construction, the timer is in an inactive state, and the alarm event is not signaled. No error checks are made to prevent exceptions propagating from the constructor. Validity checks on the handles will be performed in member functions.

CWaitableTimerSubst::Set

The Set member function sets the timer to the specified number of milliseconds.
void CWaitableTimerSubst::Set(
  DWORD dwMilliSeconds // timer interval
  );

Parameters

dwMilliseconds
Indicates the timer interval in milliseconds.

Return Value and Exceptions

If the function fails, it throws a CWin32Exception.

Remarks

The function can be called anytime. When the timer is in the active state and waiting for the time interval to elapse, it is started anew without the alarm event being set.

void CWaitableTimerSubst::Cancel

The Cancel member function interrupts the timer and causes it to enter the inactive state.
CWaitableTimerSubst::Cancel(
  );

Return Value and Exceptions

If the function fails, it throws a CWin32Exception.

Remarks

The cancel member function does not affect the state of the alarm event. All that is guaranteed is that when the cancel function returns, the timer is in the inactive state, waiting to be set off again.

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.


CWaitableTimerSubst::GetHandle

Returns a handle to the alarm event. This is the event that a thread which uses the timer should wait on. The handle is closed by the destructor.
HANDLE CWaitableTimerSubst::GetHandle(
  );

CWaitableTimerSubst Exception Handling

The implementation of CWaitableTimerSubst uses Win32 APIs. All errors are thus identified by the error code that is returned by the GetLastError() API. When such an error occurs, the CWaitableTimerSubst functions throw an exception of type CWin32Exception. CWin32Exception is a simple class that stores the error code as well as the name of the source file and the number of the line where the error occurred. The declaration of CWin32Exception can be found in the file Win32Exception.h.

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.

CWaitableTimerSubst Example

The following program can be used to test and demonstrate the functionality of the CWaitableTimerSubst class.
#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() ;
  }
  
}