写程序过程中总免不了用到锁,虽然大牛们总是推荐无锁编程,但那境界对我来说实在太远了。
项目中的数据资源的访问,少不了锁,考虑到都是读的多,写的少,于是参考网络,自己实现一个写优先的读写锁。
Windows下的:
class RWLock
{
public:
RWLock();
~RWLock();
void readLock();
void readUnlock();
void writeLock();
void writeUnlock();
private:
CEvent* eventRead;
CEvent* eventWrite;
CMutex* m_pMutex;
unsigned long waittoread,waittowrite;
unsigned long reader,writer;
};
#include "rwlock.h"
RWLock::RWLock()
{
eventRead=new CEvent(true,true);
eventWrite=new CEvent(true,false);
m_pMutex=new CMutex();
eventRead->SetEvent();
eventWrite->SetEvent();
waittoread=0;
waittowrite=0;
reader=0;
writer=0;
}
RWLock::~RWLock()
{
}
void RWLock::readLock()
{
bool loop=false;
do{
WaitForSingleObject(eventRead->m_hObject,INFINITE);
m_pMutex->Lock();
if (writer>0 || waittowrite>0)
{
loop=true;
}else{
reader++;
loop=false;
eventWrite->ResetEvent();
}
m_pMutex->Unlock();
}while(loop);
}
void RWLock::readUnlock()
{
m_pMutex->Lock();
reader--;
if ( reader==0)
{
eventWrite->SetEvent();
}
m_pMutex->Unlock();
}
void RWLock::writeLock()
{
bool loop=false;
m_pMutex->Lock();
waittowrite++;
eventRead->ResetEvent();
m_pMutex->Unlock();
do {
WaitForSingleObject(eventWrite->m_hObject,INFINITE);
m_pMutex->Lock();
if (reader>0)
{
loop=true;
}else{
loop=false;
writer++;
waittowrite--;
}
m_pMutex->Unlock();
} while(loop);
m_pMutex->Unlock();
}
void RWLock::writeUnlock()
{
m_pMutex->Lock();
writer--;
eventWrite->SetEvent();
if(waittowrite<=0)
eventRead->SetEvent();
m_pMutex->Unlock();
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Linux下的:
class RWLock
{
public:
RWLock();
~RWLock();
int readLock();
int readUnlock();
int writeLock();
int writeUnlock();
private:
pthread_mutex_t mutex;
pthread_cond_t readq,writeq;
unsigned long waittoread,waittowrite;
unsigned long reader,writer;
};
#include "rwlock.h"
RWLock::RWLock()
{
pthread_mutex_init ( &mutex,NULL );
pthread_cond_init ( &readq,NULL );
pthread_cond_init ( &writeq,NULL );
waittoread=0;
waittowrite=0;
reader=0;
writer=0;
}
RWLock::~RWLock()
{
pthread_mutex_destroy ( &mutex );
pthread_cond_destroy ( &readq );
pthread_cond_destroy ( &writeq );
}
int RWLock::readLock()
{
int value=0;
value=pthread_mutex_lock ( &mutex );
if ( value!=0 )
return value;
while ( writer>0 || waittowrite>0 )
{
waittoread++;
pthread_cond_wait ( &readq,&mutex );
waittoread--;
}
reader++;
pthread_mutex_unlock ( &mutex );
}
int RWLock::readUnlock()
{
int value=0;
value=pthread_mutex_lock ( &mutex );
if ( value!=0 )
return value;
reader--;
if ( reader==0 && waittowrite>0 )
{
pthread_cond_signal ( &writeq );
}
pthread_mutex_unlock ( &mutex );
}
int RWLock::writeLock()
{
int value=0;
value=pthread_mutex_lock ( &mutex );
if ( value!=0 )
return value;
while ( reader+writer>0 )
{
waittowrite++;
pthread_cond_wait ( &writeq,&mutex );
waittowrite--;
}
writer++;
pthread_mutex_unlock(&mutex);
}
int RWLock::writeUnlock()
{
int value=0;
value=pthread_mutex_lock ( &mutex );
if ( value!=0 )
return value;
writer--;
if(waittowrite>0)
pthread_cond_signal(&writeq);
else if(waittoread>0)
pthread_cond_broadcast(&readq);
pthread_mutex_unlock(&mutex);
}
用起来,没出什么大问题。不过,似乎还有可以优化的地方,比如Windows下的那个,应该可以将锁去掉,换成互斥代码段,据说互斥代码段比锁效率高点。而且这个锁不支持二次加锁,这个还没想好有什么简单的实现。
锁的实现并不是什么大问题,毕竟一些系统都有提供。锁的粒度,就没那么好处理了。工作中碰到的情况是,四个类A,B,C,D,A对A,A对B,B对C,都是一对多的关系,C对D是多对多的关系。觉得使用数据库太浪费,于是自己维护,在内存中组织成一颗树。如果简单的几个锁,那就会出现太多的等待,如果每个对象都单独分配一个锁,那锁就太多了,太多的内核对象,好像不是什么好现象。不知道数据库怎么实现的。
想到一个解决办法,就是单独启一个线程作数据的访问和修改操作,操作请求都封装成统一格式。其它线程要访问时就封装请求,放入队列,然后sleep。数据操作线程从队列中取出请求执行后,唤醒等待的线程。这样锁的需求就只剩一个了---队列。但省下锁,却换成了线程的频繁切换。在并发场合,单独一个操作线程,说不定还会成为性能瓶颈,难道要弄成一个线程池,让线程数随队列里的请求数量动态变化?额的神啊。
不知道hibernate怎么实现的。看来应该找时间好好看看。