Figure 1   CResGuard


 // Instances of this class will be accessed by multiple threads. So, 
 // all members of this class (except the constructor and destructor) 
 // must be thread-safe.
 class CResGuard {
 public:
    CResGuard()  { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); }
    ~CResGuard() { DeleteCriticalSection(&m_cs); }
 
    // IsGuarded is used for debugging
    BOOL IsGuarded() const { return(m_lGrdCnt > 0); }
 
 public:
     class CGuard {
     public:
         CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); };
       ~CGuard() { m_rg.Unguard(); }
 
     private:
         CResGuard& m_rg;
     };
 
 private:
    void Guard()   { EnterCriticalSection(&m_cs); m_lGrdCnt++; }
    void Unguard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); }
 
    // Guard/Unguard can only be accessed by the nested CGuard class.
    friend class CResGuard::CGuard;
 
 private:
    CRITICAL_SECTION m_cs;
    long m_lGrdCnt;   // # of EnterCriticalSection calls
 };
 

Figure 2   Using the CGuard Class


struct SomeDataStruct {
   •••
} g_SomeSharedData;

// Create a CResGuard that protects g_SomeSharedData 
// Note: The constructor initializes the critical section and 
//       the destructor deletes the critical section.
CResGuard g_rgSomeSharedData;

void AFunction () {

   // This function touches the shared data

   // Protect the resource from being accessed from multiple threads.
   CResGuard::CGuard gDummy(g_rgSomeSharedData);	
   // Enters the critical section

   // Touch the g_SomeSharedData resource
   •••

}  // Note: LeaveCriticalSection is called when gDummy goes out of scope

Figure 3   CinterlockedType


 // Instances of this class will be accessed by multiple threads. So, 
 // all members of this class (except the constructor and destructor) 
 // must be thread-safe.
 template <class TYPE>
 class CInterlockedType {
 
 public:     // Public member functions
    // Note: Constructors & destructors are always thread-safe
    CInterlockedType() { }
    CInterlockedType(const TYPE& TVal) { m_TVal = TVal; }
    virtual ~CInterlockedType()  { }
 
    // Cast operator to make writing code that uses 
    // thread-safe data type easier
    operator TYPE() const { 
 #ifdef MUTABLE_SUPPORTED
       CResGuard::CGuard x(m_rg); 
 #else
       CResGuard::CGuard x(const_cast<CResGuard&>(m_rg)); 
 #endif
       return(GetVal()); 
    }
 
 protected:  // Protected function to be called by derived class
    TYPE& GetVal() { 
       assert(m_rg.IsGuarded()); 
       return(m_TVal); 
    }
 
    const TYPE& GetVal() const { 
       assert(m_rg.IsGuarded()); 
       return(m_TVal); 
    }
 
    TYPE SetVal(const TYPE& TNewVal) { 
       assert(m_rg.IsGuarded()); 
       TYPE& TVal = GetVal();
       if (TVal != TNewVal) {
          TYPE TPrevVal = TVal;
          TVal = TNewVal;
          OnValChanged(TNewVal, TPrevVal);
       }
       return(TVal); 
    }
 
 protected:  // Overridable functions
    virtual void OnValChanged(
       const TYPE& TNewVal, const TYPE& TPrevVal) const { 
       // Nothing to do here
    }
 
 protected:  
    // Protected guard for use by derived class functions
 #ifdef MUTABLE_SUPPORTED
       mutable CResGuard m_rg;
 #else
       CResGuard m_rg;
 #endif
 
 private:    // Private data members
    TYPE m_TVal;
 };

Figure 4   CinterlockedScalar


 // Instances of this class will be accessed by multiple threads. So, 
 // all members of this class (except the constructor and destructor) 
 // must be thread-safe.
 template <class TYPE>
 class CInterlockedScalar : 
    protected CInterlockedType<TYPE> {
 
 public:
    CInterlockedScalar(TYPE TVal = 0) 
       : CInterlockedType<TYPE>(TVal) { 
    }
 
    ~CInterlockedScalar() { /* Nothing to do */ }
 
    // C++ does not allow operator cast to be inherited.
    operator TYPE() const { 
       return(CInterlockedType<TYPE>::operator TYPE()); 
    }
 
    TYPE operator=(TYPE TVal) { 
       CResGuard::CGuard x(m_rg); 
       return(SetVal(TVal)); 
    }
 
     TYPE operator++(int) {       // Postfix increment operator
       CResGuard::CGuard x(m_rg);
       TYPE TPrevVal = GetVal();
       SetVal(TPrevVal + 1);
       return(TPrevVal);          // Return value BEFORE increment
    }
 
     TYPE operator--(int) {       // Postfix decrement operator
       CResGuard::CGuard x(m_rg);
       TYPE TPrevVal = GetVal();
       SetVal(TPrevVal - 1);
       return(TPrevVal);          // Return value BEFORE decrement
    }
 
    TYPE operator += (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() +  op)); }
    TYPE operator++()            
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() +   1)); }
    TYPE operator -= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() -  op)); }
    TYPE operator--()            
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() -   1)); }
    TYPE operator *= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() *  op)); }
    TYPE operator /= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() /  op)); }
    TYPE operator %= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() %  op)); }
    TYPE operator ^= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() ^  op)); }
    TYPE operator &= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() &  op)); }
    TYPE operator |= (TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() |  op)); }
    TYPE operator <<=(TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() << op)); }
    TYPE operator >>=(TYPE op)   
       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() >> op)); }
 };

Figure 5   CwhenZero


 // Instances of this class will be accessed by multiple threads. So, 
 // all members of this class (except the constructor and destructor) 
 // must be thread-safe.
 template <class TYPE> 
 class CWhenZero : public CInterlockedScalar<TYPE> {
 public:
    CWhenZero(TYPE TVal = 0, BOOL fManualReset = TRUE) 
       : CInterlockedScalar<TYPE>(TVal) {
 
       // The event should be signaled if TVal is 0
       m_hevtZero = CreateEvent(NULL, fManualReset, (TVal == 0), NULL);
 
       // The event should be signaled if TVal is NOT 0
       m_hevtNotZero = CreateEvent(NULL, fManualReset, (TVal != 0), NULL);
    }
 
    ~CWhenZero() {
       CloseHandle(m_hevtZero);
       CloseHandle(m_hevtNotZero);
    }
 
    // C++ does not allow operator= to be inherited.
    TYPE operator=(TYPE x) { 
       return(CInterlockedScalar<TYPE>::operator=(x)); 
    }
 
    // Return handle to event signaled when value is zero
    operator HANDLE() const { return(m_hevtZero); }
 
    // Return handle to event signaled when value is not zero
    HANDLE GetNotZeroHandle() const { return(m_hevtNotZero); }
 
    // C++ does not allow operator cast to be inherited.
    operator TYPE() const { 
       return(CInterlockedScalar<TYPE>::operator TYPE()); 
    }
 
 protected:
    void OnValChanged(const TYPE& TNewVal, const TYPE& TPrevVal) const { 
       // For best performance, avoid jumping to 
       // kernel mode if we don't have to
       if ((TNewVal == 0) && (TPrevVal != 0)) {
          SetEvent(m_hevtZero);
          ResetEvent(m_hevtNotZero);
       }
       if ((TNewVal != 0) && (TPrevVal == 0)) {
          ResetEvent(m_hevtZero);
          SetEvent(m_hevtNotZero);
       }
    }
 
 private:
    HANDLE m_hevtZero;      // Signaled when data value is 0
    HANDLE m_hevtNotZero;   // Signaled when data value is not 0
 };
 
 
 #endif   // __INTERLOCKED_H__

Figure 6   IntLockTest.h


 /*************************************************************
 Module name: IntLockTest.h
 Notices: Written 1997 by Jeffrey Richter
 Description: Tests CWhenZero class.
 *************************************************************/
 #define STRICT
 #include <Windows.h>
 #include <assert.h>
 #include "Interlocked.h"
 //////////////////////////////////////////////////////////////
 // Set to TRUE when worker threads should terminate cleanly.
 BOOL g_fQuit = FALSE;
 //////////////////////////////////////////////////////////////
 DWORD WINAPI WorkerThread (LPVOID p) {
    CWhenZero<BYTE>& bVal = * (CWhenZero<BYTE> *) p;
 
    // Should worker thread terminate?
    while (!g_fQuit) {
 
       // Wait for something to do
       WaitForSingleObject(bVal.GetNotZeroHandle(), INFINITE);
 
       // If we should quit, quit
       if (g_fQuit) continue;
 
       // Do something
       MessageBox(NULL, __TEXT("We have something to do"), 
          __TEXT("Worker thread"), MB_OK);
 
       bVal--;     // We're done
 
       // Wait for all worker threads to stop
       WaitForSingleObject(bVal, INFINITE);
    }
 
    MessageBox(NULL, __TEXT("Worker is terminating"), 
       __TEXT("Worker thread"), MB_OK);
    return(0);
 }
 //////////////////////////////////////////////////////////////
 int WINAPI WinMain (HINSTANCE hinst, 
    HINSTANCE hinstPrev, LPSTR lp, int n) {
 
    // Initialize to indicate that NO worker threads have anything to do
    CWhenZero<BYTE> bVal = 0;
 
    // Create the worker threads
    const int nMaxThreads = 2;
    HANDLE hThreads[nMaxThreads];
    for (int nThread = 0; nThread < nMaxThreads; nThread++) {
       DWORD dwThreadId;
       hThreads[nThread] = CreateThread(NULL, 0, 
          WorkerThread, (PVOID) &bVal, 0, &dwThreadId);
    }
 
    do {
 
       // Find out if there is more work to be done 
       // or if the process should terminate
       n = MessageBox(NULL, 
          __TEXT("Yes: Give worker threads something to do\nNo: Quit"), 
          __TEXT("Primary thread"), MB_YESNO);
 
       // Set the flag so that the worker threads will see
       // that there is no more work to do.
       if (n == IDNO) g_fQuit = TRUE;
 
       bVal = nMaxThreads;  // Wake the worker threads
 
       if (n == IDYES) {
          // There is work to do, wait for the worker threads to finish
          WaitForSingleObject(bVal, INFINITE);
       }
 
    } while (n == IDYES);
 
    // There is no more work to do, the process wants to die.
    // Wait for the worker threads to terminate
    WaitForMultipleObjects(nMaxThreads, hThreads, TRUE, INFINITE);
 
    // Close the worker thread handles.
    for (nThread = 0; nThread < nMaxThreads; nThread++)
       CloseHandle(hThreads[nThread]);
 
    // Tell the user that the process is dying
    MessageBox(NULL, 
       __TEXT("Primary thread is terminating"), 
       __TEXT("Primary thread"), MB_OK);
 
    return(0);
 }
 //////////////////////// End Of File /////////////////////////