在一些读多写少的业务场景下,读写锁的效率是高于互斥锁的,然而c++到c++14才有读写锁,如果想在c++11中实现一套读写锁,可以参考以下实现:
//file: SharedMutex.h
#pragma once
#include <mutex>
#include <condition_variable>
class CSharedMutex
{
public:
CSharedMutex();
void lock();
bool try_lock();
void unlock();
void lock_shared();
bool try_lock_shared();
void unlock_shared();
protected:
private:
CSharedMutex(const CSharedMutex&);
const CSharedMutex& operator=(const CSharedMutex&);
class CStateData
{
public:
CStateData();
bool m_bExclusive;
unsigned int m_uSharedCount;
unsigned int m_uExclusiveWaitingBlockedCount;
protected:
private:
};
CStateData m_cState;
std::mutex m_cMutex;
std::condition_variable_any m_condShared;
std::condition_variable_any m_condExclusive;
};
//file: SharedMutex.cpp
#include "SharedMutex.h"
void CSharedMutex::lock()
{
bool bBlock = false;
std::unique_lock<std::mutex> cLock(m_cMutex);
while (m_cState.m_uSharedCount>0 || m_cState.m_bExclusive) //共享读/独占写则等待
{
if (!bBlock)
{
m_cState.m_uExclusiveWaitingBlockedCount++;
bBlock = true;
}
m_condExclusive.wait(cLock);
}
if (bBlock)
{
m_cState.m_uExclusiveWaitingBlockedCount--;
}
m_cState.m_bExclusive = true;
}
bool CSharedMutex::try_lock()
{
std::unique_lock<std::mutex> cLock(m_cMutex);
if (m_cState.m_uSharedCount > 0 || m_cState.m_bExclusive) //有读、或者写 -> 无法加锁
{
return false;
}
else
{
m_cState.m_bExclusive = true;
return true;
}
}
void CSharedMutex::unlock()
{
std::unique_lock<std::mutex> cLock(m_cMutex);
m_cState.m_bExclusive = false; // 写结束
if (m_cState.m_uExclusiveWaitingBlockedCount > 0)
{
m_condExclusive.notify_one(); // 有写等待,通知一个写
}
else
{
m_condShared.notify_all(); // 没有写等待,唤醒所有读
}
}
void CSharedMutex::lock_shared()
{
std::unique_lock<std::mutex> cLock(m_cMutex);
while (m_cState.m_bExclusive || m_cState.m_uExclusiveWaitingBlockedCount > 0) //有写或者写等待 -> 就进入读等待
{
m_condShared.wait(cLock);
}
m_cState.m_uSharedCount++;
}
bool CSharedMutex::try_lock_shared()
{
std::unique_lock<std::mutex> cLock(m_cMutex);
if (m_cState.m_bExclusive || m_cState.m_uExclusiveWaitingBlockedCount > 0) // 有写或者写等待 -> 无法共享读
{
return false;
}
else
{
m_cState.m_uSharedCount++;
return true;
}
}
void CSharedMutex::unlock_shared()
{
std::unique_lock<std::mutex> cLock(m_cMutex);
m_cState.m_uSharedCount--;
if (m_cState.m_uSharedCount == 0 && m_cState.m_uExclusiveWaitingBlockedCount > 0) // 最后一个读且有写等待->通知写
{
m_condExclusive.notify_one();
}
}
CSharedMutex::CSharedMutex()
{
}
CSharedMutex::CStateData::CStateData()
: m_uSharedCount(0)
, m_bExclusive(false)
, m_uExclusiveWaitingBlockedCount(0)
{
}
// ShareadGuard.h
#pragma once
#include "SharedMutex.h"
template<typename T>
class UniqueLock
{
public:
UniqueLock(T &cMutex)
:m_cMutex(cMutex)
, m_bLocked(true)
{
m_cMutex.lock();
}
~UniqueLock()
{
UnLock();
}
void Lock()
{
if (!m_bLocked)
{
m_cMutex.lock();
m_bLocked = true;
}
}
void UnLock()
{
if (m_bLocked)
{
m_cMutex.unlock();
m_bLocked = false;
}
}
protected:
private:
UniqueLock(const UniqueLock&);
const UniqueLock & operator=(const UniqueLock&);
T &m_cMutex;
bool m_bLocked;
};
template<typename T>
class SharedLock
{
public:
SharedLock(T &cMutex)
: m_cMutex(cMutex)
, m_bLocked(true)
{
m_cMutex.lock_shared();
}
~SharedLock()
{
UnLock();
}
void Lock()
{
if (!m_bLocked)
{
m_cMutex.lock_shared();
m_bLocked = true;
}
}
void UnLock()
{
if (m_bLocked)
{
m_cMutex.unlock_shared();
m_bLocked = false;
}
}
private:
SharedLock(const SharedLock &);
const SharedLock & operator=(const SharedLock &);
private:
T &m_cMutex;
bool m_bLocked;
};
//file: main.cpp
#include "SharedMutex.h"
#include "ShareadGuard.h"
int main()
{
CSharedMutex mtx;
SharedLock<CSharedMutex> rGuard(mtx);// 读锁, 尝试以共享的方式上锁,如果此前有其他人独占了锁,此处将阻塞
UniqueLock<CSharedMutex> wGuard(mtx);// 写锁,尝试以独占的方式上锁,如果此前有其他人以任何方式上了锁,此处将阻塞
return 0;
}