首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

用MUTEX兑现读写锁

2013-03-13 
用MUTEX实现读写锁这个需求很明确,就不罗嗦了。第一个版本:class ResManager {public:ResManager(HANDLE hH

用MUTEX实现读写锁

这个需求很明确,就不罗嗦了。

第一个版本:

class ResManager {public:    ResManager(HANDLE hHandle) : m_hHandle (hHandle) {        WaitForSingleObject(m_hHandle, INFINITE);    }    ~ResManager() {        ReleaseMutex(m_hHandle);    }private:    HANDLE m_hHandle; };class WriteMsgHelper {public:    static WriteMsgHelper* getInstance() {        if (m_pInstance == 0) {            m_pInstance = new WriteMsgHelper();            m_hMutex = CreateMutex(0, false, 0);        }        return m_pInstance;    }    void WriteMsg(const string& str) {        ResManager rm(m_hMutex);        cout << str.c_str() << endl;     }private:    WriteMsgHelper() {}    static WriteMsgHelper* m_pInstance;     static HANDLE m_hMutex; };WriteMsgHelper* WriteMsgHelper::m_pInstance = 0; HANDLE WriteMsgHelper::m_hMutex = INVALID_HANDLE_VALUE;class BaseLock {public:    virtual ~BaseLock() {}    virtual bool getLock() = 0;    virtual void releaseLock() = 0;};class WriteLock : public BaseLock {public:    WriteLock(int &iReaderCount, HANDLE &hReaderMutex)         : m_iReader_Count(iReaderCount),          m_hMutex_Reader(hReaderMutex)    {    }    bool getLock() {        WaitForSingleObject(m_hMutex_Reader, INFINITE);        if (m_iReader_Count == 0) {            return true;         }        else {            ReleaseMutex(m_hMutex_Reader);            return false;        }    }    void releaseLock() {        ReleaseMutex(m_hMutex_Reader);    }private:    HANDLE &m_hMutex_Reader;    int &m_iReader_Count; };class ReadLock : public BaseLock{public:    ReadLock(int &iReaderCount, HANDLE &hReaderMutex) : m_iReaderCount(iReaderCount), m_hMutex_ReaderCount(hReaderMutex) {}    bool getLock() {        ResManager rm(m_hMutex_ReaderCount);        m_iReaderCount++;        return true;    }    void releaseLock() {        ResManager rm(m_hMutex_ReaderCount);        m_iReaderCount--;    }private:    int &m_iReaderCount;    HANDLE &m_hMutex_ReaderCount; };struct ThreadParam {    int iThreadID;    BaseLock *pLock;    int iRand;    ThreadParam(int aiThreadID, BaseLock *apLock, int aiRand)         : iThreadID(aiThreadID), pLock(apLock), iRand(aiRand) {    } };const int g_iMaxSleepSeconds = 5; // thread try to writeDWORD WINAPI WriteThread(PVOID pvParam) {    char buf[200] = {0};    ThreadParam *pThreadParam = (ThreadParam *)pvParam;    sprintf(buf, "Thread %d try to get write lock", pThreadParam->iThreadID);    WriteMsgHelper::getInstance()->WriteMsg(buf);    bool result = pThreadParam->pLock->getLock();    if (!result) {        sprintf(buf, "Thread %d get lock failed", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);    }    else {        sprintf(buf, "Thread %d get lock successfully", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);        int iSleep = pThreadParam->iRand;        sprintf(buf, "Thread %d write %d seconds", pThreadParam->iThreadID, iSleep);        WriteMsgHelper::getInstance()->WriteMsg(buf);        Sleep(iSleep * 1000);        sprintf(buf, "Thread %d release lock", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);        pThreadParam->pLock->releaseLock();    }    delete(pThreadParam);    return 0; }// thread try to readDWORD WINAPI ReadThread(PVOID pvParam) {    char buf[200] = {0};    ThreadParam *pThreadParam = (ThreadParam*)pvParam;    sprintf(buf, "Thread %d try to get read lock", pThreadParam->iThreadID);    WriteMsgHelper::getInstance()->WriteMsg(buf);    bool result = pThreadParam->pLock->getLock();    if (!result) {        sprintf(buf, "Thread %d get lock failed", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);    }    else {        sprintf(buf, "Thread %d get lock successfully", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);        int iSleep = pThreadParam->iRand;        sprintf(buf, "Thread %d read %d seconds", pThreadParam->iThreadID, iSleep);        WriteMsgHelper::getInstance()->WriteMsg(buf);        Sleep(iSleep * 1000);        sprintf(buf, "Thread %d release lock", pThreadParam->iThreadID);        WriteMsgHelper::getInstance()->WriteMsg(buf);        pThreadParam->pLock->releaseLock();    }    delete(pThreadParam);    return 0;}int _tmain(int argc, _TCHAR* argv[]){    const int iThreadNum = 5;     HANDLE hReaderMutex = CreateMutex(0, false, 0);    int iReaderCount = 0;     WriteLock writeLock(iReaderCount, hReaderMutex);    ReadLock readLock(iReaderCount, hReaderMutex);    srand(time(0));    HANDLE hThreads[iThreadNum * 2] = {0};    for (int i=0; i<5; i++) {        // create reader        Sleep(10);        ThreadParam *pThreadParam = new ThreadParam(i * 2, &readLock, rand() % g_iMaxSleepSeconds);        hThreads[i*2] = CreateThread(0, 0, ReadThread, pThreadParam, 0, 0);        // create writer        Sleep(10);        pThreadParam = new ThreadParam(i * 2 + 1, &writeLock, rand() % g_iMaxSleepSeconds);        hThreads[i*2+1] = CreateThread(0, 0, WriteThread, pThreadParam, 0, 0);    }    WaitForMultipleObjects(iThreadNum * 2, hThreads, true, INFINITE);    return 0; }



输出:

Thread 0 try to get read lockThread 0 get lock successfullyThread 0 read 1 secondsThread 1 try to get write lockThread 2 try to get read lockThread 1 get lock failedThread 2 get lock successfullyThread 3 try to get write lockThread 2 read 0 secondsThread 4 try to get read lockThread 3 get lock failedThread 2 release lockThread 5 try to get write lockThread 4 get lock successfullyThread 6 try to get read lockThread 5 get lock failedThread 7 try to get write lockThread 4 read 3 secondsThread 6 get lock successfullyThread 8 try to get read lockThread 7 get lock failedThread 9 try to get write lockThread 6 read 3 secondsThread 8 get lock successfullyThread 9 get lock failedThread 8 read 4 secondsThread 0 release lockThread 4 release lockThread 6 release lockThread 8 release lock


其中有几个类是用来做辅助作用的,可以忽略。包括ResManager (用来管理资源), WritesgHelper(用来保证消息完整的输出到标准输出上)。

大概思路是这样的,定义了一个WriteLock类和一个ReadLock类,它们继承自BaseLock类。这样的用意是线程中使用时可以不用关心锁的类型,而是调用统一的接口就可以了。WriteLock和ReadLock实际上共享了一个mutex和一个整型变量。整型变量记录了读者的数量,而该mutex即为了保护这个变量而设。读锁每次简单的增加读者的数量,释放锁时减少读者的数量。而写锁每次要检查读者的数量,只有在读者数量为0时才进行写操作,否则写操作失败。

测试结果基本反映了我们设计的意图,读者可以并发的进行读操作,而写者操作具有排他性。但是我们发现一个问题,写者经常处于饥渴状态,以至于根本拿不到锁。第二版本我们试图改掉这个问题。读写锁有两种:第一种是强读者同步,即只要写者没有进行写操作就可以进行读操作;第二种是强读者同步,即只要读者没有进行读操作就可以进行写操作。这里先想办法实现一个简单的版本,就是写者如果申请锁失败了,不返回,而是阻塞等待。但是这个实现我大概想了想,好像只用MUTEX没有好的办法实现。我要回去再好好研究一下。大侠们有好的主意吗?

第二个版本?


 

热点排行