读写锁

多个线程产生race condition,根据业务逻辑,分为共享资源的读和写,多个线程的读不会对数据造成破坏。如果不区分读和写,每次遇到race condition便锁住不允许其他线程访问,造成效率低下。根据以上逻辑,可以用信号量来实现多个线程的共享读,互斥写。


//读写递归锁
class RWRecLock
{
public:
	typedef AutoRLockT<RWRecLock>	AutoRLock;
	typedef AutoWLockT<RWRecLock>	AutoWLock;

	RWRecLock();
	~RWRecLock();

	void readLock();

	bool tryReadLock();

	void writeLock();

	bool tryWriteLock();

	void unlock();
private:
	/// <summary> 
	/// 用于保护所有的其他成员变量,这样,对它们的操作就能够以原子操作方式来完成
	/// </summary> 
	CRITICAL_SECTION m_cs;

	
	/// <summary> 
	/// 当许多线程调用readLock,但是由于m_nActive是- 1而被拒绝访问时,
	/// 所有阅读线程均等待该信标。当最后一个正在等待的写入线程调用unlock时,
	/// 该信标被释放,其数量是m_nWaitingReaders,从而唤醒所有正在等待的阅
	/// 读线程
	/// </summary> 
	HANDLE m_hsemReaders;

	/// <summary> 
	/// 当线程调用writeLock,但是由于m_nActive大于0而被拒绝访问时,所
	/// 有写入线程均等待该信标。当一个线程正在等待时,新阅读线程将被拒绝
	/// 访问该资源。这可以防止阅读线程垄断该资源。当最后一个拥有资源访问
	/// 权的阅读线程调用unlock时,该信标就被释放,其数量是1,从而唤醒一个正
	/// 在等待的写入线程
	/// </summary> 
	HANDLE m_hsemWriters;

	/// <summary> 
	/// 表示想要访问资源的阅读线程的数量。该值被初始化为0,当m_nActive
	/// 是-1时,每当线程调用一次readLock,该值就递增1
	/// </summary> 
	int m_nWaitingReaders;

	/// <summary> 
	/// 表示想要访问资源的写入线程的数量。该值被初始化为0,当m_nActive大
	/// 于0时,每当线程调用一次WaitToWrite,该值就递增1
	/// </summary> 
	int m_nWaitingWriters;

	/// <summary> 
	/// 用于反映共享资源的当前状态。如果该值是0,那么没有线程在访问资源。
	///	如果该值大于0,这个值用于表示当前读取该资源的线程的数量。如果这个
	///	数量是负值,那么写入程序正在将数据写入该资源。唯一有效的负值是- 1
	/// </summary> 
	int m_nActive;


};

RWRecLock::RWRecLock()
{
	m_nWaitingReaders = 0;
	m_nWaitingWriters = 0;
	m_nActive = 0;
	m_hsemReaders = CreateSemaphore(NULL,0,MAXLONG,NULL);
	SORBA_ASSERT(m_hsemReaders);
	m_hsemWriters = CreateSemaphore(NULL,0,MAXLONG,NULL);
	SORBA_ASSERT(m_hsemWriters);
	InitializeCriticalSection(&m_cs);
}

RWRecLock::~RWRecLock()
{
#ifdef _DEBUG
	if(m_nActive != 0)
	{
		SORBA_ASSERT(false);
	}
#endif
	CloseHandle(m_hsemReaders);
	CloseHandle(m_hsemWriters);
	DeleteCriticalSection(&m_cs);
}

void RWRecLock::readLock()
{
	EnterCriticalSection(&m_cs);

	bool bWritePending = (m_nWaitingWriters || (m_nActive<0));

	if (bWritePending) 
	{
		++m_nWaitingReaders;
	}
	else
	{
		++m_nActive;
	}

	if(bWritePending)
	{
		LeaveCriticalSection(&m_cs);
		WaitForSingleObject(m_hsemReaders,INFINITE);
		return;
	}
	LeaveCriticalSection(&m_cs);
	
}

bool RWRecLock::tryReadLock()
{
	return false;
}

void RWRecLock::writeLock()
{
	EnterCriticalSection(&m_cs);

	bool bResourceOwned = (m_nActive != 0);

	if(bResourceOwned)
	{
		++m_nWaitingWriters;
	}
	else
	{
		m_nActive = -1;
	}

	if(bResourceOwned)
	{
		LeaveCriticalSection(&m_cs);
		WaitForSingleObject(m_hsemWriters,INFINITE);
		return;
	}
	LeaveCriticalSection(&m_cs);
}

bool RWRecLock::tryWriteLock()
{
	return false;
}

void RWRecLock::unlock()
{
	EnterCriticalSection(&m_cs);

	SORBA_ASSERT(m_nActive!=0);

	/*
	std::cout<<"m_nActive:"<<m_nActive<<std::endl;
	std::cout<<"m_nWaitingWriters:"<<m_nWaitingWriters<<std::endl;
	std::cout<<"m_nWaitingReaders:"<<m_nWaitingReaders<<std::endl;
	*/

	if(m_nActive > 0)
	{
		--m_nActive;
	}
	else
	{
		++m_nActive;
	}

	HANDLE hsem = NULL;
	LONG lCount = 1;

	if(m_nActive == 0)
	{
		//写线程优先
		if(m_nWaitingWriters > 0)
		{
			m_nActive = -1;
			--m_nWaitingWriters;
			hsem = m_hsemWriters;
			lCount = 1;
		}
		else if(m_nWaitingReaders >0)
		{
			m_nActive = m_nWaitingReaders;
			m_nWaitingReaders = 0;
			hsem = m_hsemReaders;
			lCount = m_nActive;
		}
		/*
		//读线程优先,会导致写线程饿死
		if(m_nWaitingReaders >0)
		{
			m_nActive = m_nWaitingReaders;
			m_nWaitingReaders = 0;
			hsem = m_hsemReaders;
			lCount = m_nActive;
		}
		else if(m_nWaitingWriters > 0)
		{
			m_nActive = -1;
			--m_nWaitingWriters;
			hsem = m_hsemWriters;
			lCount = 1;
		}
		*/
		else
		{
			//do nothing
		}
	}

	if(hsem != NULL)
	{
		LeaveCriticalSection(&m_cs);
		if(!ReleaseSemaphore(hsem,lCount,NULL))
		{
			SORBA_ASSERT(false);
		}
		return;
	}
	LeaveCriticalSection(&m_cs);
}

后记:读写锁的缺陷——当读写都在等待的时候,写锁优先获得,倘若写锁频繁申请,将导致读锁一直不能得到,从而造成“读饿死”。


//写线程优先
		if(m_nWaitingWriters > 0)
		{
			m_nActive = -1;
			--m_nWaitingWriters;
			hsem = m_hsemWriters;
			lCount = 1;
		}
		else if(m_nWaitingReaders >0)
		{
			m_nActive = m_nWaitingReaders;
			m_nWaitingReaders = 0;
			hsem = m_hsemReaders;
			lCount = m_nActive;
		}
		/*
		//读线程优先,会导致写线程饿死
		if(m_nWaitingReaders >0)
		{
			m_nActive = m_nWaitingReaders;
			m_nWaitingReaders = 0;
			hsem = m_hsemReaders;
			lCount = m_nActive;
		}
		else if(m_nWaitingWriters > 0)
		{
			m_nActive = -1;
			--m_nWaitingWriters;
			hsem = m_hsemWriters;
			lCount = 1;
		}
		*/
		else
		{
			//do nothing
		}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值