Interlocked.h
Upload User: wzandzl
Upload Date: 2007-07-05
Package Size: 124k
Code Size: 7k
Category:

Windows Develop

Development Platform:

Visual C++

  1. /******************************************************************************
  2. Module:  Interlocked.h
  3. Notices: Copyright (c) 2000 Jeffrey Richter
  4. ******************************************************************************/
  5. #pragma once
  6. ///////////////////////////////////////////////////////////////////////////////
  7. // Instances of this class will be accessed by multiple threads. So, 
  8. // all members of this class (except the constructor and destructor) 
  9. // must be thread-safe.
  10. class CResGuard {
  11. public:
  12.    CResGuard()  { m_lGrdCnt = 0; InitializeCriticalSection(&m_cs); }
  13.    ~CResGuard() { DeleteCriticalSection(&m_cs); }
  14.    // IsGuarded is used for debugging
  15.    BOOL IsGuarded() const { return(m_lGrdCnt > 0); }
  16. public:
  17.    class CGuard {
  18.    public:
  19.       CGuard(CResGuard& rg) : m_rg(rg) { m_rg.Guard(); };
  20.       ~CGuard() { m_rg.Unguard(); }
  21.    private:
  22.       CResGuard& m_rg;
  23.    };
  24. private:
  25.    void Guard()   { EnterCriticalSection(&m_cs); m_lGrdCnt++; }
  26.    void Unguard() { m_lGrdCnt--; LeaveCriticalSection(&m_cs); }
  27.    // Guard/Unguard can only be accessed by the nested CGuard class.
  28.    friend class CResGuard::CGuard;
  29. private:
  30.    CRITICAL_SECTION m_cs;
  31.    long m_lGrdCnt;   // # of EnterCriticalSection calls
  32. };
  33. ///////////////////////////////////////////////////////////////////////////////
  34. // Instances of this class will be accessed by multiple threads. So, 
  35. // all members of this class (except the constructor and destructor) 
  36. // must be thread-safe.
  37. template <class TYPE>
  38. class CInterlockedType {
  39. public:     // Public member functions
  40.    // Note: Constructors & destructors are always thread safe
  41.    CInterlockedType() { }
  42.    CInterlockedType(const TYPE& TVal) { m_TVal = TVal; }
  43.    virtual ~CInterlockedType()  { }
  44.    // Cast operator to make writing code that uses 
  45.    // thread-safe data type easier
  46.    operator TYPE() const { 
  47.       CResGuard::CGuard x(m_rg); 
  48.       return(GetVal()); 
  49.    }
  50. protected:  // Protected function to be called by derived class
  51.    TYPE& GetVal() { 
  52.       chASSERT(m_rg.IsGuarded()); 
  53.       return(m_TVal); 
  54.    }
  55.    const TYPE& GetVal() const { 
  56.       assert(m_rg.IsGuarded()); 
  57.       return(m_TVal); 
  58.    }
  59.    TYPE SetVal(const TYPE& TNewVal) { 
  60.       chASSERT(m_rg.IsGuarded()); 
  61.       TYPE& TVal = GetVal();
  62.       if (TVal != TNewVal) {
  63.          TYPE TPrevVal = TVal;
  64.          TVal = TNewVal;
  65.          OnValChanged(TNewVal, TPrevVal);
  66.       }
  67.       return(TVal); 
  68.    }
  69. protected:  // Overridable functions
  70.    virtual void OnValChanged(
  71.       const TYPE& TNewVal, const TYPE& TPrevVal) const { 
  72.       // Nothing to do here
  73.    }
  74. protected:  
  75.    // Protected guard for use by derived class functions
  76.       mutable CResGuard m_rg;
  77. private:    // Private data members
  78.    TYPE m_TVal;
  79. };
  80. ///////////////////////////////////////////////////////////////////////////////
  81. // Instances of this class will be accessed by multiple threads. So, 
  82. // all members of this class (except the constructor and destructor) 
  83. // must be thread-safe.
  84. template <class TYPE>
  85. class CInterlockedScalar : protected CInterlockedType<TYPE> {
  86. public:
  87.    CInterlockedScalar(TYPE TVal = 0) : CInterlockedType<TYPE>(TVal) { 
  88.    }
  89.    ~CInterlockedScalar() { /* Nothing to do */ }
  90.    // C++ does not allow operator cast to be inherited.
  91.    operator TYPE() const { 
  92.       return(CInterlockedType<TYPE>::operator TYPE()); 
  93.    }
  94.    TYPE operator=(TYPE TVal) { 
  95.       CResGuard::CGuard x(m_rg); 
  96.       return(SetVal(TVal)); 
  97.    }
  98.    TYPE operator++(int) {    // Postfix increment operator
  99.       CResGuard::CGuard x(m_rg);
  100.       TYPE TPrevVal = GetVal();
  101.       SetVal((TYPE) (TPrevVal + 1));
  102.       return(TPrevVal);      // Return value BEFORE increment
  103.    }
  104.    TYPE operator--(int) {    // Postfix decrement operator.
  105.       CResGuard::CGuard x(m_rg);
  106.       TYPE TPrevVal = GetVal();
  107.       SetVal((TYPE) (TPrevVal - 1));
  108.       return(TPrevVal);      // Return value BEFORE decrement
  109.    }
  110.    TYPE operator += (TYPE op)   
  111.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() +  op)); }
  112.    TYPE operator++()            
  113.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() +   1)); }
  114.    TYPE operator -= (TYPE op)   
  115.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() -  op)); }
  116.    TYPE operator--()            
  117.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() -   1)); }
  118.    TYPE operator *= (TYPE op)   
  119.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() *  op)); }
  120.    TYPE operator /= (TYPE op)   
  121.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() /  op)); }
  122.    TYPE operator %= (TYPE op)   
  123.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() %  op)); }
  124.    TYPE operator ^= (TYPE op)   
  125.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() ^  op)); }
  126.    TYPE operator &= (TYPE op)   
  127.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() &  op)); }
  128.    TYPE operator |= (TYPE op)   
  129.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() |  op)); }
  130.    TYPE operator <<=(TYPE op)   
  131.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() << op)); }
  132.    TYPE operator >>=(TYPE op)   
  133.       { CResGuard::CGuard x(m_rg); return(SetVal(GetVal() >> op)); }
  134. };
  135. ///////////////////////////////////////////////////////////////////////////////
  136.    
  137. // Instances of this class will be accessed by multiple threads. So, 
  138. // all members of this class (except the constructor and destructor) 
  139. // must be thread-safe.
  140. template <class TYPE> 
  141. class CWhenZero : public CInterlockedScalar<TYPE> {
  142. public:
  143.    CWhenZero(TYPE TVal = 0, BOOL fManualReset = TRUE) 
  144.       : CInterlockedScalar<TYPE>(TVal) {
  145.       // The event should be signaled if TVal is 0
  146.       m_hevtZero = CreateEvent(NULL, fManualReset, (TVal == 0), NULL);
  147.       // The event should be signaled if TVal is NOT 0
  148.       m_hevtNotZero = CreateEvent(NULL, fManualReset, (TVal != 0), NULL);
  149.    }
  150.    ~CWhenZero() {
  151.       CloseHandle(m_hevtZero);
  152.       CloseHandle(m_hevtNotZero);
  153.    }
  154.    // C++ does not allow operator= to be inherited.
  155.    TYPE operator=(TYPE x) { 
  156.       return(CInterlockedScalar<TYPE>::operator=(x)); 
  157.    }
  158.    // Return handle to event signaled when value is zero
  159.    operator HANDLE() const { return(m_hevtZero); }
  160.    // Return handle to event signaled when value is not zero
  161.    HANDLE GetNotZeroHandle() const { return(m_hevtNotZero); }
  162.    // C++ does not allow operator cast to be inherited.
  163.    operator TYPE() const { 
  164.       return(CInterlockedScalar<TYPE>::operator TYPE()); 
  165.    }
  166. protected:
  167.    void OnValChanged(const TYPE& TNewVal, const TYPE& TPrevVal) const { 
  168.       // For best performance, avoid jumping to 
  169.       // kernel mode if we don't have to
  170.       if ((TNewVal == 0) && (TPrevVal != 0)) {
  171.          SetEvent(m_hevtZero);
  172.          ResetEvent(m_hevtNotZero);
  173.       }
  174.       if ((TNewVal != 0) && (TPrevVal == 0)) {
  175.          ResetEvent(m_hevtZero);
  176.          SetEvent(m_hevtNotZero);
  177.       }
  178.    }
  179. private:
  180.    HANDLE m_hevtZero;      // Signaled when data value is 0
  181.    HANDLE m_hevtNotZero;   // Signaled when data value is not 0
  182. };
  183. //////////////////////////////// End of File //////////////////////////////////