Monday, January 24, 2011

ReadWriteLock em C++ no Windows com Mutex e Event

Assim como o Java possui o ReentrantReadWriteLock, o C# possui ReaderWriterLock. Que tal então uma classe que implementa o controle de concorrência para leitura e escrita em C++ nas aplicações Windows.


A classe ReadWriteLock permite liberar acesso paralelo para threads que desejam acessar um objeto ou trecho de código somente para leitura e garante exclusividade para no caso de acesso para escrita. Código fonte abaixo:

#include <windows.h>

class ReadWriteLock
{
public:
    ReadWriteLock(void);
    ~ReadWriteLock(void);

private:
    HANDLE hSyncOperationsMutex;
private:
    HANDLE hCanReadEvent;
private:
    HANDLE hCanWriteEvent;
private:
    HANDLE hReadGroup[2];
private:
    HANDLE hWriteGroup[2];
private:
    int readerThreads;

public:
    void writeLock();
public:
    void writeUnlock();
public:
    void readLock();
public:
    void readUnlock();
};

ReadWriteLock::ReadWriteLock(void)
{
    this->hSyncOperationsMutex = CreateMutex(NULL, FALSE, NULL);
    this->hCanReadEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
    this->hCanWriteEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

    this->hReadGroup[0] = hSyncOperationsMutex;
    this->hReadGroup[1] = hCanReadEvent;
    this->hWriteGroup[0] = hSyncOperationsMutex;
    this->hWriteGroup[1] = hCanWriteEvent;

    this->readerThreads=0;
}

ReadWriteLock::~ReadWriteLock(void)
{
    CloseHandle(this->hSyncOperationsMutex);
    CloseHandle(this->hCanReadEvent);
    CloseHandle(this->hCanWriteEvent);
}

void ReadWriteLock::writeLock()
{
    //wait for write flag and mutex
    WaitForMultipleObjects(2, this->hWriteGroup, TRUE, INFINITE);

    ResetEvent(this->hCanReadEvent);
    ResetEvent(this->hCanWriteEvent);

    //dont release the mutex
}

void ReadWriteLock::writeUnlock()
{
    //dont get the already taken mutex

    SetEvent(this->hCanReadEvent);
    SetEvent(this->hCanWriteEvent);

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

void ReadWriteLock::readLock()
{
    //wait for read flag and mutex
    WaitForMultipleObjects(2, this->hReadGroup, TRUE, INFINITE);

    //lock write operations on first thread
    if ( this->readerThreads == 0 ) {
        ResetEvent(this->hCanWriteEvent);
    }
    //increase reader count
    this->readerThreads++;

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

void ReadWriteLock::readUnlock()
{
    //get mutex
    WaitForSingleObject(this->hSyncOperationsMutex, INFINITE);

    //decrease reader count
    this->readerThreads--;
    //unlock write operations on last reader thread
    if ( this->readerThreads == 0 ) {
        SetEvent(this->hCanWriteEvent);
    }

    //release mutex
    ReleaseMutex(this->hSyncOperationsMutex);
}

Exemplo de uso da classe:

//cria objeto
ReadWriteLock* rwLocks = new ReadWriteLock();

void LeObjetos() {
    rwLocks->readLock();

    //nesse trecho todas as threads tem acesso simultaneo

    rwLocks->readUnlock();
}

void AlteraObjetos() {
    rwLocks->writeLock();

    //esse trecho é acessado por um objeto de cada vez
    //e também bloqueia acesso ao trecho de leitura

    rwLocks->writeUnlock();
}

No comments:

Post a Comment