linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)
前一篇文章分析了Windows slim read/write lock的工作原理。我們知道它的設(shè)計(jì)相當(dāng)精妙,于是我們可以借鑒它的思路來設(shè)計(jì)linux下的讀寫鎖。
在這個(gè)讀寫鎖的設(shè)計(jì)上,需要注意的是linux和windows有以下幾點(diǎn)區(qū)別:
(1)windows使用的keyedevent機(jī)制需要使用linux下的機(jī)制代替。這里我們選用futex機(jī)制來模擬。linux下的futex機(jī)制對外表現(xiàn)為下面這個(gè)接口:
int futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3)
但是由于沒有公開提供該接口,所有我們需要使用syscall來調(diào)用它,如下:
#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)
在這里我們主要使用單個(gè)線程死等和喚醒單個(gè)線程兩項(xiàng)操作。關(guān)于futex的其他知識可以參考搜索引擎,不再贅述。
(2)futex的wake機(jī)制和KeyedEvent有所區(qū)別。NtReleaseKeyedEvent喚醒等待線程時(shí),如果此時(shí)尚不存在等待者,NtReleaseKeyedEvent會阻塞,直到有等待者出現(xiàn)。但是,通過在linux環(huán)境 “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的返回值是實(shí)際喚醒線程的個(gè)數(shù),
while(1 != (futex_wake_single(tmp2)))
{
unsigned int n = 0;
RtlBackoff(&n);
}
(3)linux下的_mm_pause并不是真的調(diào)用了cpu的pause指令,而是用nop指令代替,這和VC的編譯結(jié)果是不一樣的,因此需要實(shí)現(xiàn)一個(gè)自己的__mm_pause:
__inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__mm_pause (void)
{
__asm__ __volatile__ ("pause" : : :"memory");
}
(4)關(guān)于函數(shù)局部變量要對齊到16字節(jié)的問題,在現(xiàn)在新版本的gcc編譯環(huán)境下可以不考慮,gcc默認(rèn)是對齊到16字節(jié)的。當(dāng)然也可以指定函數(shù)屬性,如下:
void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockExclusive(SRWLOCK* pSRWLock);
void __attribute__((force_align_arg_pointer)) RtlAcquireSRWLockShared(SRWLOCK* pSRWLock);
(5)VC提供的interlockedXXX系列函數(shù)相當(dāng)豐富,需要使用gcc提供的__syncXXXX系列的十來個(gè)函數(shù)來代替,相當(dāng)?shù)疤邸?/p>
由于原生態(tài)的讀寫鎖CRWLock不支持同一線程的遞歸鎖操作,所有增加了一個(gè)CRWLockRecur類,其中記錄了線程id用于實(shí)現(xiàn)遞歸鎖功能。CRWLock類的代碼經(jīng)過了30個(gè)線程1.5億次隨機(jī)加解鎖操作測試,能夠穩(wěn)定工作。好了下面貼出頭文件部分代碼,完整代碼比較長,就不貼了,可以到http://download.csdn.net/detail/yichigo/7603735下載參考,完全免費(fèi)。歡迎指正!
#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
// 自己實(shí)現(xiàn)一個(gè)
__inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
__mm_pause (void)
{
__asm__ __volatile__ ("pause" : : :"memory");
}
#define SRWLockSpinCount 1024
#define Busy_Lock1// 已經(jīng)有人獲取了鎖
#define Wait_Lock2// 有人等待鎖
#define Release_Lock4// 說明已經(jīng)有人釋放一次鎖
#define Mixed_Lock8// 共享鎖、獨(dú)占鎖并存
#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
//
//
// 增加一個(gè)獲取獨(dú)占鎖線程id記錄
// 實(shí)現(xiàn)獨(dú)占鎖遞歸支持
//
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
總結(jié)
以上是生活随笔為你收集整理的linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言设计一个按时间片轮转法实现处理器调
- 下一篇: linux packet socket,