我常用的 C++ 读写锁

锁操作是为了线程安全,下面写一个我常用的 C++ 自旋锁,简单高效。

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

template<typename T>
class RSpinLock
{   
    public:
        RSpinLock( T * addr ) : m_addr(addr)
        {   
            while( true )
            {   
                T old = * m_addr;
                old &= (T)~1;
                if( __sync_bool_compare_and_swap( m_addr, old, old | 2 ) ) //set reader
                {   
                    __sync_fetch_and_add( m_addr, 4 ); //add a reader
                    break;                            
                }   
            }   

        }   
        ~RSpinLock( )
        {   
            __sync_fetch_and_sub( m_addr, 4 );  
            __sync_bool_compare_and_swap( m_addr, 2, 0 ); //clear reader
        }   
    private: T * m_addr;
};  

template<typename T>
class WSpinLock
{   
    public:
        WSpinLock( T * addr ) : m_addr(addr)
        {   
            while( !__sync_bool_compare_and_swap( m_addr, 0, 1 ) );
        }   
        ~WSpinLock( )
        {   
            *m_addr = 0;
        }   
    private: T * m_addr;
};  

写自旋锁中的 __sync_bool_compare_and_swap(m_addr, 0, 1) 函数表示当调用构造函数时将 m_addr 指向的值为 0 时,将其交换为 1 并返回 ture ,相当于某个进程拿到了锁。

当另外的进程调用构造函数时,由于 m_addr 已经指向 1,__sync_bool_compare_and_swap(m_addr, 0, 1) 则返回 false ,那么这个进程就被锁在了 while 循环中。直到拿到锁的进程调用析构函数将 m_addr 指向的值再次修改为 0,释放调锁。

需要上锁时直接在代码块中构造 WSpinLock 对象即可。

{
    WSpinLock<uint32_t> locker( &m_bf_meta.Ptr()->tItemMeta[index].iLock );
    /* 上锁后的操作 */
}// 跳出代码块后,自动调用 locker 析构函数,释放掉锁

读自旋锁测试代码如下:

#include "RWSpinLock.h"
#include <stdio.h>

int main()
{
        char x = 0;
        {
                RSpinLock<char> l1(&x);
                {
                        RSpinLock<char> l2(&x);
                        {
                                RSpinLock<char> l3(&x);
                                printf("%d\n", x);
                        }
                        printf("%d\n", x);
                }
                printf("%d\n", x);
        }
        printf("%d\n", x);
        return 0;
}

猜你喜欢

转载自blog.csdn.net/u012675539/article/details/52015450