自旋锁 SpinLock

工作中某些需要,正好在codeproject 找到了,有兴趣看看~~

// (C) Copyright 2001
// Craig Henderson
//
// cdm.henderson@virgin.net
// http://homepage.virgin.net/cdm.henderson
//
// SpinLock.h


#ifndef __SPINLOCK_H_
#define __SPINLOCK_H_


// if we haven't got a DBG_FN macro defined for debug output, then
// define it to be a simple TRACE
#ifndef DBG_FN
#   define DBG_FN TRACE
#endif

// if we haven't got a TRACE macro defined for debug output, then
// define a dummy to compile to a null statement
#ifndef TRACE
#   define TRACE    1? (void)0 : (void)0
#endif  // TRACE

// if we haven't got an ASSERT macro defined for debugging, then
// define a dummy to compile to a null statement
#ifndef ASSERT
#   define ASSERT   1? (void)0 : (void)0
#endif  // ASSERT


// scope the class inside a namespace
// this is always good practice to avoid clashes
// with classes from external sources
namespace cdmh {


// helper function to determine if the runtime operating system is a
// member of the WindowNT family
// Returns:
//      true    for WinNT 4, Window 2000 and WinXP
//      false   for Windows 95, 98, 98SE and Me
inline bool IsWindowsNT(void)
{
    static OSVERSIONINFO osvi        = { sizeof(OSVERSIONINFO) };
    static bool          got_version = false;

    if (!got_version)
        got_version = (::GetVersionEx(&osvi) == TRUE);
    return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
}


// we use a trick with a numeric template parameter to enable multiple locks
// and to avoid the need for a .cpp implementation file just to instantiate
// the static m_lock member
// each object that is instantiated with the same template parameter value
// will share the lock, and different values of the template parameter will
// identify independent locks
// For example, an if an application has two classes of worker threads, each
// class of thread requires exclusive access to a shared resource, but these
// resources are independent of each other, then one class of thread can use
// CSpinLock<1> and the other can use CSpinLock<2>.
template<size_t N=1>
class CSpinLock
{
  private:
    // this is the value that will spin around the threads. the thread
    // with this value in it's m_plock member is the one that holds the
    // lock
    // this simplifies debugging as it is easy to see if a lock is held
    // by a lock object by casting the m_plock member to a char * in the
    // watch window
    enum { LockValue = 'kcol' };

    // we declare a static member which will provide us with a cross-thread
    // value storing the actual value of the lock. each object that is
    // instantiated with the same template value will share the lock, and
    // different values of the template parameter will identify independent
    // locks
    static long m_lock;

    // this is the actual lock pointer that is used in the class.
    // it can be set through a parameter to the ctor, or by default,
    // uses the above member
    mutable long *m_plock;

    // SwitchToThread() is only available on the WindowsNT family, so we bind
    // dynamically at run-time so that we can still support Win9x family
    typedef BOOL (* PFNSwitchToThread)(void);
    PFNSwitchToThread m_pfnSwitchToThread;

  protected:
    // if these methods are not defined, then the compiler
    // will generate them if we try to use them.
    // we declare them but do not implement them as they are unused,
    // but if they are called in error, then we will get a linker
    // error. if we did not do this, the compiler will generate a basic
    // memcpy version, but that will be incorrect as the m_data vector
    // will not get copied correctly
    CSpinLock(const CSpinLock &);
    CSpinLock &operator=(const CSpinLock &);

  public:
    // this is the only public ctor
    // the parameter is optional, and can be omitted in most circumstances
    // to provide the default functionality. if the outer algorithm wants to
    // control the lock object more closely, then this parameter can be used
    explicit CSpinLock(long *plock = 0)
    {
        // if we haven't been supplied a lock variable, then use our own
        if (plock == NULL)
            m_plock = &m_lock;
        else
            m_plock = plock;

        // SwitchToThread() is only available on the WindowsNT family, so
        // we bind dynamically at run-time so that we can still support
        // Win9x family
        m_pfnSwitchToThread = NULL;
        if (cdmh::IsWindowsNT())
        {
            HINSTANCE hInst = ::LoadLibrary("Kernel32.dll");
            if (hInst != NULL)
                m_pfnSwitchToThread = (PFNSwitchToThread)::GetProcAddress(hInst, "SwitchToThread");
        }
    }

    // class dtor
    ~CSpinLock()
    {
        // if this assert fails, then the object still holds the lock
        // when in is going out of scope
        ASSERT(!this->has_lock());
    }

    void lock(void) const
    {
        // output to the debugger
        DBG_FN("0x%08x waiting for lock\n", this);

        // this is why it is called a spin lock; we simply sit in a loop
        // until the lock is released by the holding object. to make the
        // algorithm more efficient, we reliquish the processor to another
        // thread if we fail to get the lock
        // note that this is inefficient for anything more than the smallest
        // interval, as the execution thread does not block while the lock
        // is held
        while (::InterlockedExchange(m_plock, LockValue) != 0)
        {
            TRACE("0x%08x can't get lock\n", this);

            if (m_pfnSwitchToThread)
                m_pfnSwitchToThread();
        }
    }

    // release the lock
    void unlock(void) const
    {
        // if this assert fails, then the object does not have the lock
        // while this is not an error in itself, and will not have any
        // adverse side effects, it generally signifies an error in the
        // outer algorithm
        ASSERT(this->has_lock());

        // reset the lock value
        ::InterlockedExchange(m_plock, 0);

        // output to the debugger
        TRACE("0x%08x released lock\n", this);
    }

    // returns true/false to signify if the object currently holds the lock
    bool has_lock(void) const
    {
        return (*m_plock == LockValue);
    }
};


// instantiate the static memory and initialise it
// to zero - the unlocked state
template<int N> long CSpinLock<N>::m_lock = 0;


}   // namespace cdmh

#endif __SPINLOCK_H_

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值