linux 下实现高性能读写锁(read/write lock)

前一篇文章分析了Windows slim read/write lock的工作原理。我们知道它的设计相当精妙,于是我们可以借鉴它的思路来设计linux下的读写锁。

在这个读写锁的设计上,需要注意的是linux和windows有以下几点区别:

(1)windows使用的keyedevent机制需要使用linux下的机制代替。这里我们选用futex机制来模拟。linux下的futex机制对外表现为下面这个接口:

int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)

但是由于没有公开提供该接口,所有我们需要使用syscall来调用它,如下:

#define futex(addr1, op, val, rel, addr2, val3) \
				syscall(SYS_futex, addr1, op, val, rel, addr2, val3)
#define futex_wait_always(addr1) \
				syscall(SYS_futex, addr1, FUTEX_WAIT, *(int*)(addr1), 0, 0, 0)
#define futex_wake_single(addr1) \
				syscall(SYS_futex, addr1, FUTEX_WAKE, 1, 0, 0, 0)

在这里我们主要使用单个线程死等和唤醒单个线程两项操作。关于futex的其他知识可以参考搜索引擎,不再赘述。

(2)futex的wake机制和KeyedEvent有所区别。NtReleaseKeyedEvent唤醒等待线程时,如果此时尚不存在等待者,NtReleaseKeyedEvent会阻塞,直到有等待者出现。但是,通过在linux环境 “Linux version 3.2.0-23-generic  (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu4) ) #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 ”下 的测试,FUTEX_WAKE在没有等待者的情况下任然会直接返回,不会等待,于是采用的下面的代码模拟NtReleaseKeyedEvent。要注意到,FUTEX_WAKE的返回值是实际唤醒线程的个数,

while(1 != (futex_wake_single(tmp2)))
{
	unsigned int n = 0;
	RtlBackoff(&n);
}


(3)linux下的_mm_pause并不是真的调用了cpu的pause指令,而是用nop指令代替,这和VC的编译结果是不一样的,因此需要实现一个自己的__mm_pause:

__inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__mm_pause (void)
{
	__asm__ __volatile__ ("pause" : : :"memory");
}

 

(4)关于函数局部变量要对齐到16字节的问题,在现在新版本的gcc编译环境下可以不考虑,gcc默认是对齐到16字节的。当然也可以指定函数属性,如下:

void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockExclusive(SRWLOCK* pSRWLock);
void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockShared(SRWLOCK* pSRWLock);

 

(5)VC提供的interlockedXXX系列函数相当丰富,需要使用gcc提供的__syncXXXX系列的十来个函数来代替,相当蛋疼。

 

由于原生态的读写锁CRWLock不支持同一线程的递归锁操作,所有增加了一个CRWLockRecur类,其中记录了线程id用于实现递归锁功能。CRWLock类的代码经过了30个线程1.5亿次随机加解锁操作测试,能够稳定工作。好了下面贴出头文件部分代码,完整代码比较长,就不贴了,可以到http://download.csdn.net/detail/yichigo/7603735下载参考,完全免费。欢迎指正!

 

#ifndef __RW_LOCK_H__
#define __RW_LOCK_H__

#if defined(_WIN32) || defined(WIN32) || defined(_WIN64)
#if !defined(RWL_WINDOWS)
#define RWL_WINDOWS
#endif // WIN32 or _WIN32
#elif defined(__linux__) || defined(__linux)
#if !defined(RWL_LINUX)
#define RWL_LINUX
#endif
#endif // not RWL_WINDOWS


#ifdef RWL_WINDOWS
#include 
#else
#include 
#include 
#include 
#include 
#include 
#include 
#endif

#ifdef RWL_WINDOWS

#if !defined(ASSERT)
#define ASSERT(f) ((f) || (__debugbreak(),0))
#endif

#else /// linux

#define ASSERT assert
//
// int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3);
#define futex(addr1, op, val, rel, addr2, val3) \
				syscall(SYS_futex, addr1, op, val, rel, addr2, val3)
#define futex_wait_always(addr1) \
				syscall(SYS_futex, addr1, FUTEX_WAIT, *(int*)(addr1), 0, 0, 0)
#define futex_wake_single(addr1) \
				syscall(SYS_futex, addr1, FUTEX_WAKE, 1, 0, 0, 0)
//
// linux下的_mm_pause不是真正的pause
// 自己实现一个
__inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__mm_pause (void)
{
	__asm__ __volatile__ ("pause" : : :"memory");
}


#define SRWLockSpinCount 1024
#define Busy_Lock		1	// 已经有人获取了锁
#define Wait_Lock		2	// 有人等待锁
#define Release_Lock	4	// 说明已经有人释放一次锁
#define Mixed_Lock		8	// 共享锁、独占锁并存

#define EXTRACT_ADDR(s)	((s) & (~0xf)) // 去掉低4位

#endif


#ifdef RWL_WINDOWS

class CRWLock
{
public:
	CRWLock();
	~CRWLock();
	void ExclusiveLock();
	void SharedLock();
	void ReleaseExclusiveLock();
	void ReleaseSharedLock();
private:
	SRWLOCK m_SRWLock;
};

#else /// linux

class CRWLock
{
	struct SRWLOCK {                            
		size_t Ptr;                                       
	};   

	struct _SyncItem
	{
		int ifutex;
		_SyncItem* back;
		_SyncItem* notify;
		_SyncItem* next;
		size_t shareCount;
		size_t flag;	
	};

public:
	CRWLock();
	~CRWLock();
	void ExclusiveLock();
	void SharedLock();
	void ReleaseExclusiveLock();
	void ReleaseSharedLock();

private:
	void RtlInitializeSRWLock(SRWLOCK* pSRWLock);
	void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockExclusive(SRWLOCK* pSRWLock);
	void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockShared(SRWLOCK* pSRWLock);
	void RtlReleaseSRWLockExclusive(SRWLOCK* pSRWLock);
	void RtlReleaseSRWLockShared(SRWLOCK *pSRWLock);
	void RtlpWakeSRWLock(SRWLOCK* pSRWLock, size_t st);
	void RtlBackoff(unsigned int *pCount);
	void RtlpOptimizeSRWLockList(SRWLOCK* pSRWLock, size_t st);

private:
	SRWLOCK m_SRWLock;
};
#endif

//////////////////////////////////////////////////////////////////////////
//
// 增加一个获取独占锁线程id记录
// 实现独占锁递归支持
//
class CRWLockRecur : public CRWLock
{
public:
	CRWLockRecur()
	{
		m_tid = -1;
		m_nRecursion = 0;
	}
	~CRWLockRecur()
	{

	}
	void OwnLock()
	{
		if (m_tid != GetTid())
		{
			ExclusiveLock();
			m_tid = GetTid();
		}
		 
		m_nRecursion++;
	}
	void ShareLock()
	{
		SharedLock();
	}
	void UnOwnLock()
	{
		m_nRecursion--;
		 
		if (0 == m_nRecursion)
		{
			m_tid = 0;
			ReleaseExclusiveLock();
		}
	}
	void UnShareLock()
	{
		ReleaseSharedLock();
	}
private:
	size_t GetTid()
	{
#ifdef RWL_WINDOWS
		return GetCurrentThreadId();
#else
		return pthread_self();
#endif
	}
private:
	size_t m_tid;
	unsigned int m_nRecursion;
};

#endif


 


 


 

 

 

 

 

 

 

你可能感兴趣的:(linux 下实现高性能读写锁(read/write lock))