home *** CD-ROM | disk | FTP | other *** search
- //
- // Atomic ints are good for counters, etc... All integer operations
- // on them are defined.
- //
- // Modification History:
- //
- // 14-Jan-1989 JEF
- // Added 'value' member function to both classes.
- //
- // 04-Jan-1989 JEF
- // Include lock/unlock pair around operator INT in both classes.
- //
- // 28-Dec-1989 JEF
- // Add class HC_AtomicInt. This new version of an atomic integer utilizes
- // the HC_Spinlock, providing faster atomic integer operations when there is
- // high contention for the atomic integer.
- //
-
-
- //
- // Binary op
- //
- // return the value at the time of the lock acquisition
- //
- #define AIOP(op)\
- inline int operator/**/op/**/(int x) \
- { \
- lock(); register int tmp = ai_val op x; unlock(); \
- return tmp; \
- }
-
- //
- // Unary op
- //
- #define AIUNOP(op)\
- inline int operator/**/op/**/() \
- { \
- lock(); register int tmp = ai_val/**/op; unlock(); \
- return tmp; \
- }
-
-
- //
- // Original atomic integer class.
- //
- class AtomicInt {
- Spinlock ai_lock;
- int ai_val;
- public:
- AtomicInt()
- { ai_val = 0; }
- AtomicInt(int x)
- { ai_val = x; }
- AtomicInt(AtomicInt& x) // should we lock x?
- { ai_val = x.ai_val;}
- ~AtomicInt()
- { unlock(); }
- operator int()
- { lock(); register int tmp = ai_val; unlock();
- return tmp; }
- void lock() // Careful....
- { ai_lock.lock(); }
- void unlock()
- { ai_lock.unlock(); }
- int& val() // use at your own risk
- { return ai_val; }
- int value() // retrieve current value safely
- { lock(); register int tmp = ai_val; unlock();
- return tmp; }
- AIOP(=)
- AIOP(+=)
- AIOP(*=)
- AIOP(/=)
- AIOP(%=)
- AIOP(^=)
- AIOP(&=)
- AIOP(|=)
- AIOP(<<=)
- AIOP(>>=)
- AIUNOP(++) /* pre inc only */
- AIUNOP(--) /* post inc only */
- int preinc()
- { lock(); register int tmp = ++ai_val; unlock();
- return tmp; }
- int postinc()
- { lock(); register int tmp = ai_val++; unlock();
- return tmp; }
- int predec()
- { lock(); register int tmp = --ai_val; unlock();
- return tmp; }
- int postdec()
- { lock(); register int tmp = ai_val--; unlock();
- return tmp; }
- // Should probably have the rest of the operators here too...
- };
-
-
- //
- // Atomic integer class specialized for use in high-contention situations.
- //
- // The best 'C++' way to do this is probably to make the AtomicInt functions
- // lock and unlock be virtual, and to then derive class HC_AtomicInt from
- // class AtomicInt, providing new lock and unlock functions specific to the
- // HC_Spinlock (as given below). However, the performance of the member
- // functions of the new derived class is poor compared to the performance
- // realized when a new base class is created (by copying and modifying the
- // original base class). In the interest of speed, we'll go with the new
- // base class instead of the derived class.
- //
-
- //
- // The clean (but SLOW) way... (note - must make ai_val in base class
- // be protected).
- //
- //class HC_AtomicInt : public AtomicInt {
- // HC_Spinlock hc_ai_lock;
- //public:
- // HC_AtomicInt (); // base class constructor
- // HC_AtomicInt (int x) : (x) {} // is called to do
- // HC_AtomicInt (AtomicInt& x) : (x) {} // all the work
- //
- // ~HC_AtomicInt ()
- // { unlock(); }
- //
- // //
- // // Make base class lock and unlock functions be virtual. Then
- // // override them with new versions specific to the high-contention
- // // spinlock.
- // //
- // void lock () // Careful....
- // {
- // hc_ai_lock.lock ();
- // cout << "ai - derived class lock (HC_Spinlock.lock)\n";
- // cout.flush ();
- // }
- //
- // void unlock ()
- // {
- // cout << "ai - derived class unlock (HC_Spinlock.unlock)\n";
- // cout.flush ();
- // hc_ai_lock.unlock();
- // }
- //};
-
-
- //
- // The fast way...
- //
- class HC_AtomicInt {
- HC_Spinlock ai_lock;
- int ai_val;
- public:
- HC_AtomicInt()
- { ai_val = 0; }
- HC_AtomicInt(int x)
- { ai_val = x; }
- HC_AtomicInt(HC_AtomicInt& x) // should we lock x?
- { ai_val = x.ai_val;}
- ~HC_AtomicInt()
- { unlock(); }
- operator int()
- { lock(); register int tmp = ai_val; unlock();
- return tmp; }
- void lock() // Careful....
- { ai_lock.lock(); }
- void unlock()
- { ai_lock.unlock(); }
- int& val() // use at your own risk
- { return ai_val; }
- int value() // retrieve current value safely
- { lock(); register int tmp = ai_val; unlock();
- return tmp; }
- AIOP(=)
- AIOP(+=)
- AIOP(*=)
- AIOP(/=)
- AIOP(%=)
- AIOP(^=)
- AIOP(&=)
- AIOP(|=)
- AIOP(<<=)
- AIOP(>>=)
- AIUNOP(++) /* pre inc only */
- AIUNOP(--) /* post inc only */
- int preinc()
- { lock(); register int tmp = ++ai_val; unlock();
- return tmp; }
- int postinc()
- { lock(); register int tmp = ai_val++; unlock();
- return tmp; }
- int predec()
- { lock(); register int tmp = --ai_val; unlock();
- return tmp; }
- int postdec()
- { lock(); register int tmp = ai_val--; unlock();
- return tmp; }
- // Should probably have the rest of the operators here too...
- };
-
-