锁操作是为了线程安全,下面写一个我常用的 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;
}