从网上的一段代码修改过来的,只是把结构明晰了些而已.
自己已经测试过了,不过这玩意太复杂,没啥信心,测试用的是一个vector,随机插入,遍历读取.3个线程写,10个线程读,运行4小时,读取2000万次,写入1600万次,貌似没啥问题,在这里分享下,有兴趣的可以试试.定义:
class CCriticalLock
{
private:
CRITICAL_SECTION section;
public:
CCriticalLock()
{
::InitializeCriticalSectionAndSpinCount(&section,10);
}
~CCriticalLock()
{
DeleteCriticalSection(&section);
}
void Lock()
{
EnterCriticalSection(&section);
}
void Unlock()
{
LeaveCriticalSection(&section);
}
operator const LPCRITICAL_SECTION(){return &section;}
};
class CAutoCLock
{
private:
CCriticalLock* pcs;
public:
CAutoCLock(CCriticalLock &srpcs):pcs(&srpcs)
{
pcs->Lock();
}
~CAutoCLock()
{
pcs->Unlock();
}
};
class CMyEvent
{
protected:
HANDLE  hEvent;
public:
CMyEvent(BOOL bManualReset=FALSE, BOOL bInitialState=FALSE, LPTSTR lpName=NULL):hEvent(NULL)
{
hEvent=::CreateEvent(NULL,bManualReset,bInitialState,lpName);
}
CMyEvent(DWORD  dwDesiredAccess,BOOL  bInheritHandle,LPCTSTR  lpName):hEvent(NULL)
{
hEvent=::OpenEvent(dwDesiredAccess,bInheritHandle,lpName );
}
~CMyEvent()
{
if(hEvent!=NULL)
{
::CloseHandle(hEvent);
}
}
inline operator HANDLE(){return hEvent;}
inline BOOL  SetEvent()
{
return ::SetEvent(hEvent);
}
inline BOOL  PulseEvent()
{
return ::PulseEvent(hEvent);
}
inline BOOL  ResetEvent()
{
return ::ResetEvent(hEvent);
}
inline BOOL Wait(DWORD time=INFINITE)
{
return WAIT_TIMEOUT!=::WaitForSingleObject(hEvent,time);
}
};
class ReadWriteLock
{
public:
int    m_currentLevel;
int    m_readCount;  
CMyEvent m_unlockEvent;
CCriticalLock m_accessMutex;
CCriticalLock m_csStateChange;
public:
enum{LOCK_LEVEL_NONE,LOCK_LEVEL_WRITE,LOCK_LEVEL_READ};
ReadWriteLock():m_unlockEvent(TRUE, FALSE)
{
m_currentLevel = LOCK_LEVEL_NONE;
m_readCount    = 0;
}
~ReadWriteLock()
{
} void readlock()
{
CAutoCLock al(m_accessMutex);
switch(m_currentLevel)
{
case LOCK_LEVEL_NONE:
case LOCK_LEVEL_READ:
{
}break;
case LOCK_LEVEL_WRITE:
{
m_unlockEvent.Wait();
}break;
}
CAutoCLock al2(m_csStateChange);
m_currentLevel = LOCK_LEVEL_READ;
m_readCount ++;
m_unlockEvent.ResetEvent();
}
void writelock()
{
CAutoCLock al(m_accessMutex);
switch(m_currentLevel)
{
case LOCK_LEVEL_NONE:
break;
case LOCK_LEVEL_WRITE:
case LOCK_LEVEL_READ:
{
m_unlockEvent.Wait();
}break;
}
CAutoCLock al2(m_csStateChange);
m_currentLevel = LOCK_LEVEL_WRITE;
m_unlockEvent.ResetEvent();
} // lock() bool unlock()
{
CAutoCLock al2(m_csStateChange);
if ( m_currentLevel == LOCK_LEVEL_READ )
{
m_readCount --;
if ( m_readCount == 0 )
{
m_currentLevel = LOCK_LEVEL_NONE;
m_unlockEvent.SetEvent();
}
}
else if ( m_currentLevel == LOCK_LEVEL_WRITE )
{
m_currentLevel = LOCK_LEVEL_NONE;
m_unlockEvent.SetEvent();
} return true;
}
};
class CAutoRWLock
{
ReadWriteLock *rwl;
public:
CAutoRWLock(ReadWriteLock &lock,bool readonly=true):rwl(&lock)
{
if(readonly)
rwl->readlock();
else
rwl->writelock();
}
~CAutoRWLock()
{
rwl->unlock();
}
};测试代码vector<CStringW> list_test;
ReadWriteLock list_test_lock;
LONG readtime=0,writetime=0;
DWORD WINAPI testthread(LPVOID)
{
DWORD id=::GetCurrentThreadId();
while(true)
{
CStringW str;
{
CAutoRWLock al(list_test_lock);
for(vector<CStringW>::const_iterator i=list_test.begin();
i!=list_test.end();i++)
{
str.AppendFormat(L"%s ",*i);
}
//if(!str.IsEmpty())
//wprintf(L"%04x:%d\n",id,list_test.size());
}
::InterlockedIncrement(&readtime);
}
return 0;
}
void write()
{
srand(::GetTickCount());
int p=1;
CStringW i_str;
while(true)
{
ATLASSERT(list_test.size()<=101);
{
CAutoRWLock al(list_test_lock,false);
if(list_test.size()>100)
{
list_test.clear();
p=1;
}
i_str.Format(L"%d",p);
if(list_test.size()>0)
{
int pos=rand()%list_test.size();
list_test.insert(list_test.begin()+pos,i_str);
}
else
list_test.push_back(i_str);
}
p++;
::InterlockedIncrement(&writetime);
}
}
DWORD WINAPI testthread_write(LPVOID)
{
write();
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
//int kk()
//int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
for(int i=0;i<10;i++)
{
CloseHandle(CreateThread(0,0,testthread,0,0,0));
}
for(int i=0;i<2;i++)
{
CloseHandle(CreateThread(0,0,testthread_write,0,0,0));
}
write();
        return 0;
}大家都试试哈,反馈下结果

解决方案 »

  1.   

    整理下
    定义class CCriticalLock
    {
    private:
    CRITICAL_SECTION section;
    public:
    CCriticalLock()
    {
    ::InitializeCriticalSectionAndSpinCount(&section,10);
    }
    ~CCriticalLock()
    {
    DeleteCriticalSection(&section);
    }
    void Lock()
    {
    EnterCriticalSection(&section);
    }
    void Unlock()
    {
    LeaveCriticalSection(&section);
    }
    operator const LPCRITICAL_SECTION(){return &section;}
    };
    class CAutoCLock
    {
    private:
    CCriticalLock* pcs;
    public:
    CAutoCLock(CCriticalLock &srpcs):pcs(&srpcs)
    {
    pcs->Lock();
    }
    ~CAutoCLock()
    {
    pcs->Unlock();
    }
    };
    class CMyEvent
    {
    protected:
    HANDLE  hEvent;
    public:
    CMyEvent(BOOL bManualReset=FALSE, BOOL bInitialState=FALSE, LPTSTR lpName=NULL):hEvent(NULL)
    {
    hEvent=::CreateEvent(NULL,bManualReset,bInitialState,lpName);
    }
    CMyEvent(DWORD  dwDesiredAccess,BOOL  bInheritHandle,LPCTSTR  lpName):hEvent(NULL)
    {
    hEvent=::OpenEvent(dwDesiredAccess,bInheritHandle,lpName );
    }
    ~CMyEvent()
    {
    if(hEvent!=NULL)
    {
    ::CloseHandle(hEvent);
    }
    }
    inline operator HANDLE(){return hEvent;}
    inline BOOL  SetEvent()
    {
    return ::SetEvent(hEvent);
    }
    inline BOOL  PulseEvent()
    {
    return ::PulseEvent(hEvent);
    }
    inline BOOL  ResetEvent()
    {
    return ::ResetEvent(hEvent);
    }
    inline BOOL Wait(DWORD time=INFINITE)
    {
    return WAIT_TIMEOUT!=::WaitForSingleObject(hEvent,time);
    }
    };
    class ReadWriteLock
    {
    public:
    int    m_currentLevel;
    int    m_readCount; 
    CMyEvent m_unlockEvent;
    CCriticalLock m_accessMutex;
    CCriticalLock m_csStateChange;
    public:
    enum{LOCK_LEVEL_NONE,LOCK_LEVEL_WRITE,LOCK_LEVEL_READ};
    ReadWriteLock():m_unlockEvent(TRUE, FALSE)
    {
    m_currentLevel = LOCK_LEVEL_NONE;
    m_readCount    = 0;
    }
    ~ReadWriteLock()
    {
    }void readlock()
    {
    CAutoCLock al(m_accessMutex);
    switch(m_currentLevel)
    {
    case LOCK_LEVEL_NONE:
    case LOCK_LEVEL_READ:
    {
    }break;
    case LOCK_LEVEL_WRITE:
    {
    m_unlockEvent.Wait();
    }break;
    }
    CAutoCLock al2(m_csStateChange);
    m_currentLevel = LOCK_LEVEL_READ;
    m_readCount ++;
    m_unlockEvent.ResetEvent();
    }
    void writelock()
    {
    CAutoCLock al(m_accessMutex);
    switch(m_currentLevel)
    {
    case LOCK_LEVEL_NONE:
    break;
    case LOCK_LEVEL_WRITE:
    case LOCK_LEVEL_READ:
    {
    m_unlockEvent.Wait();
    }break;
    }
    CAutoCLock al2(m_csStateChange);
    m_currentLevel = LOCK_LEVEL_WRITE;
    m_unlockEvent.ResetEvent();
    } // lock()bool unlock()
    {
    CAutoCLock al2(m_csStateChange);
    if ( m_currentLevel == LOCK_LEVEL_READ )
    {
    m_readCount --;
    if ( m_readCount == 0 )
    {
    m_currentLevel = LOCK_LEVEL_NONE;
    m_unlockEvent.SetEvent();
    }
    }
    else if ( m_currentLevel == LOCK_LEVEL_WRITE )
    {
    m_currentLevel = LOCK_LEVEL_NONE;
    m_unlockEvent.SetEvent();
    }return true;
    }
    };
    class CAutoRWLock
    {
    ReadWriteLock *rwl;
    public:
    CAutoRWLock(ReadWriteLock &lock,bool readonly=true):rwl(&lock)
    {
    if(readonly)
    rwl->readlock();
    else
    rwl->writelock();
    }
    ~CAutoRWLock()
    {
    rwl->unlock();
    }
    }; 测试vector <CStringW> list_test;
    ReadWriteLock list_test_lock;
    LONG readtime=0,writetime=0;
    DWORD WINAPI testthread(LPVOID)
    {
    DWORD id=::GetCurrentThreadId();
    while(true)
    {
    CStringW str;
    {
    CAutoRWLock al(list_test_lock);
    for(vector <CStringW>::const_iterator i=list_test.begin();
    i!=list_test.end();i++)
    {
    str.AppendFormat(L"%s ",*i);
    }
    //if(!str.IsEmpty())
    //wprintf(L"%04x:%d\n",id,list_test.size());
    }
    ::InterlockedIncrement(&readtime);
    }
    return 0;
    }
    void write()
    {
    srand(::GetTickCount());
    int p=1;
    CStringW i_str;
    while(true)
    {
    ATLASSERT(list_test.size() <=101);
    {
    CAutoRWLock al(list_test_lock,false);
    if(list_test.size()>100)
    {
    list_test.clear();
    p=1;
    }
    i_str.Format(L"%d",p);
    if(list_test.size()>0)
    {
    int pos=rand()%list_test.size();
    list_test.insert(list_test.begin()+pos,i_str);
    }
    else
    list_test.push_back(i_str);
    }
    p++;
    ::InterlockedIncrement(&writetime);
    }
    }
    DWORD WINAPI testthread_write(LPVOID)
    {
    write();
    return 0;
    }
    int _tmain(int argc, _TCHAR* argv[])
    //int kk()
    //int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
    {
    for(int i=0;i <10;i++)
    {
    CloseHandle(CreateThread(0,0,testthread,0,0,0));
    }
    for(int i=0;i <2;i++)
    {
    CloseHandle(CreateThread(0,0,testthread_write,0,0,0));
    }
    write();
            return 0;
      

  2.   

    另外,这个锁是不能等待超时的,需要等待超时的,只要把CCriticalLock m_accessMutex 改回原版的互斥量就可以了,不过涉及到内核对象,性能上可能会有些影响.
    根据MS在.net2.0里实现的读写锁的说法,锁递归还是不要实现为好,写锁递归有很多逻辑上的问题,需要更加复杂的变量保护.更加难以调试.
    锁升降级的问题我完全没头绪,不知道应该如何实现.MS要做一个升级保护,就是可升级读锁定时,可读但是不能写,太复杂搞不定.大家努力哈.